Single cell seq after sorting for PhenoID

sample1 = Neurons1 sample2 = Neurons2 sample3 = Glia1 - Astrocytes (CD44+) sample4 = Glia2 - Radial Glia (CD44-)

In HPC I have run steps of scrnabox (custom pipeline in progress) 1. Cell Ranger for feature seq 2. Create Seurat Objects 3. Apply minimum filtering and calculate percent mitochondria.

I have technical 3 replicates with hashtag labels at this point I haven’t yet demultiplex the hashtags. The data here will be treated as one sample. I sorted three separate samples and pooled them together.

# set up the environment
Warning messages:
1: R graphics engine version 15 is not supported by this version of RStudio. The Plots tab will be disabled until a newer version of RStudio is installed. 
2: In readRDS(path) : error reading from connection
library(Seurat)
Attaching SeuratObject
Attaching sp
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(Matrix)
library(ggplot2)
Learn more about the underlying theory at https://ggplot2-book.org/
#rm(list = ls())

Read in the seurat objects made in compute canada


# this seems to never load I'll use step 3 output that has some filtering 
# nFeature_RNA > 180 and percent.mt < 25

pathway <- "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/"

Neurons1 <- readRDS(paste(pathway,"seu1.rds",sep = ""))
Neurons2 <- readRDS(paste(pathway,"seu2.rds",sep = ""))
Glia1 <- readRDS(paste(pathway,"seu3.rds",sep = ""))
Glia2 <- readRDS(paste(pathway,"seu4.rds",sep = ""))

Neurons1
Neurons2
Glia1
Glia2

Have a look at the objects that already have some filtering

See the violin plots


VlnPlot(Neurons1, pt.size = 0.10, features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 3)

VlnPlot(Neurons1, pt.size = 0.10, features = c("nFeature_RNA"), y.max = 500)
VlnPlot(Neurons1, pt.size = 0.10, features = c("nCount_RNA"), y.max = 2000)


# filter more cells

Neuron1.ft <- subset(Neurons1, subset = nFeature_RNA > 250 & nCount_RNA > 250 & nCount_RNA < 10000) 
Neuron1.ft

# 33541 features across 1833 samples

Filters out specific genes


# filter out MALAT1 super high expression

seu.ft <- seu[!grepl("MALAT1", rownames(seu)), ]
seu.ft <- seu.ft[!grepl("^MT-", rownames(seu.ft)), ]

# this filtered object might cluster differently

PCA and UMAP


seu.q <- NormalizeData(seu.ft, normalization.method = "LogNormalize", scale.factor = 10000)
seu.q <- FindVariableFeatures(seu.q, selection.method = "vst", nfeatures = 2000)
seu.q <- ScaleData(seu.q)
seu.q <- RunPCA(seu.q)
seu.q <- RunUMAP(seu.q, reduction = "pca", n.neighbors = 25, dims = 1:30, min.dist = 0.25, spread = 2)

Try to find doublets with doublet finder

remotes::install_github('chris-mcginnis-ucsf/DoubletFinder')
suppressMessages(require(DoubletFinder))

seu.d = FindVariableFeatures(seu.q, verbose = F)
seu.d = ScaleData(seu.d, vars.to.regress = c("nFeature_RNA", "percent.mt"),
    verbose = F)
seu.d = RunPCA(seu.d, verbose = F, npcs = 20)
seu.d = RunUMAP(seu.d, dims = 1:10, verbose = F)

nExp <- round(ncol(seu.d) * 0.06)  # expect 6% doublets
seu.d <- doubletFinder_v3(seu.d, pN = 0.25, pK = 0.09, nExp = nExp, PCs = 1:10)


# name of the DF prediction can change, so extract the correct column name.
DF.name = colnames(seu.d@meta.data)[grepl("DF.classification", colnames(seu.d@meta.data))]



cowplot::plot_grid(ncol = 2, DimPlot(seu.d, group.by = "orig.ident") + NoAxes(),
    DimPlot(seu.d, group.by = DF.name) + NoAxes())

Do the double cells have more genes than the singlet??


VlnPlot(seu.d, features = "nFeature_RNA", group.by = DF.name, pt.size = 0.1)
# yes 

Remove the doublets


seu.d <- seu.d[, seu.d@meta.data[, DF.name]== "Singlet"]
dim(seu.d)
dim(seu)

# removed about 100 cells

Run clustering


seu.q <- FindNeighbors(seu.d, dims = 1:25, k.param = 43)
seu.q <- FindClusters(seu.q, resolution = c(0,0.2,0.4,0.6))
seu.q <- FindClusters(seu.q, resolution = c(1.2))

library(clustree)
clustree(seu.q, prefix = "RNA_snn_res.")
DimPlot(seu.q)

Look at the predictions of cell types in seurat label transfer

3 organoid datasets



# SNCA and control midbrain organoids 165 days in culture
MBO <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/AST23_BrainComm/MBOclusters_names29072021.rds")

# Midbrain  AIW002 120 days in culture
AIWMBO <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/AIWtrio120days/MOintegratedClusterK123res0.8.names_nov16_2021")

# Midbrain AIW002 60 days in culture

AIW60 <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/AIWtrio60days/AWI002ParkinKOPinkKO60days_labels_14052022.rds")


# query
#seu.q <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/NeuronsFilteredSeu28092022.RDS")


#first predict with the MBO data
Idents(MBO) <- "cluster_labels"
DefaultAssay(MBO) <- "RNA"

# find the reference anchors
print("finding reference anchors")
anchors <- FindTransferAnchors(reference = MBO ,query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = MBO$cluster_labels)
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$MBOAST23.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'MBOAST23.pred', label = TRUE)
 
## check the proportion of cell types predicted in each cluster
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$predicted.id))
pr.t.lables <- as.data.frame(prop.table(table(seu.q$RNA_snn_res.0.2, seu.q$predicted.id)))
t.lables$Freq <- as.double(t.lables$Freq)


# try bar chart
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity")

# clusters don't break up by the predicted cell types

############ another predictions now using the AIW organoids

Idents(AIWMBO) <- "res08names"
DefaultAssay(AIWMBO) <- "RNA"

anchors <- FindTransferAnchors(reference = AIWMBO ,query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = AIWMBO$res08names)
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$MBOAIW.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'MBOAIW.pred', label = TRUE)
 
## check the proportion of cell types predicted in each cluster
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$predicted.id))
pr.t.lables <- as.data.frame(prop.table(table(seu.q$RNA_snn_res.0.2, seu.q$predicted.id)))
t.lables$Freq <- as.double(t.lables$Freq)


# try bar chart
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity")

# the predicted cell types make more sense from the AIW002 organoid
# now predict with the AIW002 60 days organoid

Idents(AIW60) <- "cluster.ids"
DefaultAssay(AIW60) <- "RNA"

anchors <- FindTransferAnchors(reference = AIW60, query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = AIW60$cluster.ids) 
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$AIW60.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'AIW60.pred', label = TRUE)
 
## check the proportion of cell types predicted in each cluster
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$predicted.id))
pr.t.lables <- as.data.frame(prop.table(table(seu.q$RNA_snn_res.0.2, seu.q$predicted.id)))
t.lables$Freq <- as.double(t.lables$Freq)

# try bar chart
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity")

# save ojbect with predicitons
saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Neurons2PredictionsSeu30092022.RDS")

Look at the cell type predictions in each cluster - Neurons 1

# AIW002 160 days predictions
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.6, seu.q$MBOAIW.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 
top.pred.celltype.AIW120 <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(1, Freq))

# AIW002 160 days predictions
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.6, seu.q$AIW60.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 
top.pred.celltype.AIW60 <-as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(1, Freq))

# AST23 65 days predictions
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.6, seu.q$MBOAST23.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 
top.pred.celltype.AST23 <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(1, Freq))


pred.table <- merge(top.pred.celltype.AIW120,top.pred.celltype.AIW60, by = 'Var1')
pred.table <- merge(pred.table, top.pred.celltype.AST23, by = 'Var1')
pred.table

Based on the 3 different predictions I can lable the cell types

0 - NPC or early neurons 1 - immature excitatory neurons 2 - NPC or early neurons 3 - RG or Oligos 4- Dopaminergic neurons - possibly early 5 - NPC or early neurons 6 - Radial GLia

Predictions with the DA subtypes from

# read in the 
seu.q <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Neuron1LabledSeu30092022.RDS")

DimPlot(seu.q)

Use the Bhaduri dataset

I will also find markers and look at a list of neuronal markers


Idents(seu.q) <- 'RNA_snn_res.0.6'
ClusterMarkers <- FindAllMarkers(seu.q, only.pos = TRUE)

top5 <- ClusterMarkers %>% group_by(cluster) %>% top_n(n=5, wt = avg_log2FC)
DoHeatmap(seu.q, features = top5$gene, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')

write.csv(ClusterMarkers,"/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/Neurons1ClusterMarkers7.csv")

Explore some Gene expression levels

feature_list = c("MKI67","SOX2","POU5F1","DLX2","PAX6","SOX9","HES1","NES","RBFOX3","MAP2","NCAM1","CD24","GRIA2","GRIN2B","GABBR1","GAD1","GAD2","GABRA1","GABRB2","TH","ALDH1A1","LMX1B","NR4A2","CORIN","CALB1","KCNJ6","CXCR4","ITGA6","SLC1A3","CD44","AQP4","S100B", "PDGFRA","OLIG2","MBP","CLDN11","VIM","VCAM1")

DoHeatmap(seu.q, features = feature_list, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = feature_list) +RotatedAxis()

PD_poulin = c("TH","SLC6A3","SLC18A2","SOX6","NDNF","SNCG","ALDH1A1","CALB1","TACR2","SLC17A6","SLC32A1","OTX2","GRP","LPL","CCK","VIP")

DoHeatmap(seu.q, features = PD_poulin, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = PD_poulin)+RotatedAxis()

ealryNeur = c("DCX","NEUROD1","TBR1")
proliferation = c("PCNA","MKI67")
neuralstem = c("SOX2","NES","PAX6","MASH1")

feature_list <- c("DCX","NEUROD1","TBR1","PCNA","MKI67","SOX2","NES","PAX6","MASH1")
DoHeatmap(seu.q, features = feature_list, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = feature_list)+RotatedAxis()
# no proliferation marker expression  PCNA or MKI67
# cluster 4 DA neurons - shows early neuron marker and low PAX 4
# cluster 3 has higher SOX2 - neuroblast marker / NPC marker

mat_neuron = c("RBFOX3","SYP","DLG45","VAMP1","VAMP2","TUBB3","SYT1","BSN","HOMER1","SLC17A6") 
# NeuN is FOX3 - RBFOX3
# PSD95 also SP-90 or DLG4
# VGLUT2 is SLC17A6
DoHeatmap(seu.q, features = mat_neuron, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
# cluster 4 also show mature neuron markers
DotPlot(seu.q, features = mat_neuron)+RotatedAxis()
# excitatory neuron markers
ex = c("GRIA2","GRIA1","GRIA4","GRIN1","GRIN2B","GRIN2A","GRIN3A","GRIN3","GRIP1","CAMK2A")
DoHeatmap(seu.q, features = ex, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = ex)+RotatedAxis()
# inhibitory neuron markers
inh = c("GAD1","GAD2", "GAT1","PVALB","GABR2","GABR1","GBRR1","GABRB2","GABRB1","GABRB3","GABRA6","GABRA1","GABRA4","TRAK2")
DoHeatmap(seu.q, features = inh, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = inh)+RotatedAxis()
# cluster 4 is more excitatory than inhbitory but neither marker set has much expression 

Checkout the Enricher cell type libraries from

# test markers for the 7 clusters in Neurons1 

library(devtools)
install_github("wjawaid/enrichR")
library(enrichR)


setEnrichrSite("Enrichr") # Human genes
# list of all the databases

dbs <- listEnrichrDbs()
dbs
# libaries with cell types

db <- c('Allen_Brain_Atlas_up','Descartes_Cell_Types_and_Tissue_2021',
        'CellMarker_Augmented_2021','Azimuth_Cell_Types_2021')

# enrichr(genes, databases = NULL)

N1.c0 <- ClusterMarkers %>% filter(cluster == 0 & avg_log2FC > 0)
genes <- N1.c0$gene

N1.c0.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c0.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c0.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c0.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c0.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c0.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c0.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

# cluster 0 could be hypothalmus, DA neurons A13

N1.c1 <- ClusterMarkers %>% filter(cluster == 1 & avg_log2FC > 0)
genes <- N1.c1$gene

N1.c1.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c1.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c1.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c1.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c1.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c1.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c1.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c1.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c1.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4

# cluster 1; olfactory bulb, neural plate, maybe Radial Glia, 
N1.c2 <- ClusterMarkers %>% filter(cluster == 2 & avg_log2FC > 0)
genes <- N1.c2$gene

N1.c2.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c2.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c2.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c2.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c2.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c2.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c2.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c2.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c2.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4

# cluster 2 some brain nucleus, neural stem

N1.c3 <- ClusterMarkers %>% filter(cluster == 3 & avg_log2FC > 0)
genes <- N1.c3$gene

N1.c3.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c3.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c3.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c3.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c3.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c3.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c3.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c3.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c3.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4

# cluster 3 stromal cell of thymus, embryonic astrocytes, OPC, NK cells, monocytes

N1.c4 <- ClusterMarkers %>% filter(cluster == 4 & avg_log2FC > 0)
genes <- N1.c4$gene

N1.c4.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c4.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c4.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c4.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c4.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c4.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c4.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c4.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c4.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4

# Dentate gyrus - different cortical layers, neurons, neurons, NPC, neurons GABA,GLUT

N1.c5 <- ClusterMarkers %>% filter(cluster == 5 & avg_log2FC > 0)
genes <- N1.c5$gene

N1.c5.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c5.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c5.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c5.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c5.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c5.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c5.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c5.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c5.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4

# cluster 5 hippocampus, endothelial cells, pericytes

N1.c6 <- ClusterMarkers %>% filter(cluster == 6 & avg_log2FC > 0)
genes <- N1.c6$gene

N1.c6.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c6.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c6.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c6.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c6.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c6.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c6.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c6.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c6.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4

# cluster 6 brain cortex, shwann cell, endothelial, pericyte, GABA

After predicting with the brain data I think using a higher cluster number will work better

pred.table <- merge(df.top.AST23, df.top.aiw60, by = 'I', all = TRUE)
pred.table <- merge(pred.table, df.top.aiw120, by = 'I')
pred.table <- merge(pred.table, df.top.Bha, by = 'I')
Warning in merge.data.frame(pred.table, df.top.Bha, by = "I") :
  column names ‘Var1.x’, ‘Var2.x’, ‘Freq.x’, ‘Var1.y’, ‘Var2.y’, ‘Freq.y’ are duplicated in the result
pred.table

Library of tissue cell types for up regulated genes per cluster 0 - hypothalmus, DA A13 1- neural plate, Radial Glia 2 - Neural stem 3 - stromal, astro OPC 4 - Neurons 5 - endothelial, pericyte 6 - maybe neurons maybe not

By the combined information - annotate the clusters in Neurons1

#Based on the 3 different predictions I can lable the cell types

#0 - NPC or early neurons
#1 - immature excitatory neurons
#2 - NPC or early neurons
#3 - RG or Oligos
#4- Dopaminergic neurons - possibly early
#5 - NPC or early neurons
#6 - Radial Glia

Idents(seu.q) <- 'RNA_snn_res.0.6'
cluster.ids <- c("ImmatureNeurons","Neurons","NPC","OPC-RG","DAneurons",
                 "Other","RG")
unique(seu.q$RNA_snn_res.0.6)

names(cluster.ids) <- levels(seu.q)
seu.q <- RenameIdents(seu.q, cluster.ids)
seu.q$subgroups <- Idents(seu.q)

DimPlot(seu.q, reduction = "umap", label = TRUE, group.by = 'subgroups', repel = TRUE)


saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Neuron1LabledSeu30092022.RDS")
library(clustree)
clustree(seu.q)

After predicting with the brain data Bhaduri Midbrain and Striatum - choose main cell types to label Tried the predictions with more clusters 0-9 res 1.2

Next Repeat everything for Neurons2

# explore filtering
seu <- Neurons2
seu
VlnPlot(seu, pt.size = 0.10, features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 3)

VlnPlot(seu, pt.size = 0.10, features = c("nFeature_RNA"), y.max = 2000)
VlnPlot(seu, pt.size = 0.10, features = c("nFeature_RNA"), y.max = 350)
VlnPlot(seu, pt.size = 0.10, features = c("nCount_RNA"), y.max = 2000)

# filter more cells

seu.ft <- subset(seu, subset = nFeature_RNA > 300 & nCount_RNA > 500 & nCount_RNA < 10000) 
seu.ft

# 17604 samples with 250 nFeature_RNA
# 9657 with  nFeature 300 and nCOunt 500

Doublet finder

suppressMessages(require(DoubletFinder))

# filtering out MALAT1 and mitochondrial genes

seu.ft <- seu.ft[!grepl("MALAT1", rownames(seu)), ]
seu.ft <- seu.ft[!grepl("^MT-", rownames(seu.ft)), ]

# like in the tutorial I'm following MALAT1 is the top most expressed gene.  The top genes are a lot of MT and Ribosomal genes

seu.ft[["percent.rb"]] <- PercentageFeatureSet(seu.ft, pattern = "^RP")

seu.d = NormalizeData(seu.ft)
seu.d = FindVariableFeatures(seu.d, verbose = F)
seu.d = ScaleData(seu.d, vars.to.regress = c("nFeature_RNA", "percent.mt"),
    verbose = F)
seu.d = RunPCA(seu.d, verbose = F, npcs = 30)
seu.d = RunUMAP(seu.d, dims = 1:10, verbose = F)

nExp <- round(ncol(seu.d) * 0.08)  # expect more doublets because there is a lot more cells
seu.d <- doubletFinder_v3(seu.d, pN = 0.25, pK = 0.09, nExp = nExp, PCs = 1:10)


# name of the DF prediction can change, so extract the correct column name.
DF.name = colnames(seu.d@meta.data)[grepl("DF.classification", colnames(seu.d@meta.data))]


cowplot::plot_grid(ncol = 2, DimPlot(seu.d, group.by = "orig.ident") + NoAxes(),
    DimPlot(seu.d, group.by = DF.name) + NoAxes())

VlnPlot(seu.d, features = "nFeature_RNA", group.by = DF.name, pt.size = 0.1)

Remove the doublet cells


seu.d <- seu.d[, seu.d@meta.data[, DF.name]== "Singlet"]
dim(seu.d)
dim(seu)
# 9657 cells pre filter
# 8884 cells after filtering
# note the percent doubles expected is close to the percent detected

Repeat workflow with doublet removed data and find clusters for



seu <- NormalizeData(seu.d, normalization.method = "LogNormalize", scale.factor = 10000)
seu <- FindVariableFeatures(seu, selection.method = "vst", nfeatures = 2000)
seu <- ScaleData(seu)
seu <- RunPCA(seu)
seu <- RunUMAP(seu, reduction = "pca", n.neighbors = 43, dims = 1:30)
DimPlot(seu, reduction = "umap")

seu.q <- FindNeighbors(seu, dims = 1:25, k.param = 43)
seu.q <- FindClusters(seu.q, resolution = c(0,0.2,0.4,0.6))

library(clustree)
clustree(seu.q)

DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.2')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.4')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.6')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.1.2')

Label cell types using the label transfer




# SNCA and control midbrain organoids 165 days in culture
MBO <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/AST23_BrainComm/MBOclusters_names29072021.rds")

# Midbrain  AIW002 120 days in culture
AIWMBO <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/AIWtrio120days/MOintegratedClusterK123res0.8.names_nov16_2021")

# Midbrain AIW002 60 days in culture

AIW60 <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/AIWtrio60days/AWI002ParkinKOPinkKO60days_labels_14052022.rds")


# query
#seu.q <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/NeuronsFilteredSeu28092022.RDS")


#first predict with the MBO data
Idents(MBO) <- "cluster_labels"
DefaultAssay(MBO) <- "RNA"

# find the reference anchors
print("finding reference anchors")
anchors <- FindTransferAnchors(reference = MBO ,query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = MBO$cluster_labels)
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$MBOAST23.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'MBOAST23.pred', label = TRUE)
 
## check the proportion of cell types predicted in each cluster
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$predicted.id))
pr.t.lables <- as.data.frame(prop.table(table(seu.q$RNA_snn_res.0.2, seu.q$predicted.id)))
t.lables$Freq <- as.double(t.lables$Freq)


# try bar chart
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity")

# clusters don't break up by the predicted cell types

############ another predictions now using the AIW organoids

Idents(AIWMBO) <- "res08names"
DefaultAssay(AIWMBO) <- "RNA"

anchors <- FindTransferAnchors(reference = AIWMBO ,query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = AIWMBO$res08names)
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$MBOAIW.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'MBOAIW.pred', label = TRUE)
 
## check the proportion of cell types predicted in each cluster
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$predicted.id))
pr.t.lables <- as.data.frame(prop.table(table(seu.q$RNA_snn_res.0.2, seu.q$predicted.id)))
t.lables$Freq <- as.double(t.lables$Freq)


# try bar chart
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity")

# the predicted cell types make more sense from the AIW002 organoid
# now predict with the AIW002 60 days organoid

Idents(AIW60) <- "cluster.ids"
DefaultAssay(AIW60) <- "RNA"

anchors <- FindTransferAnchors(reference = AIW60, query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = AIW60$cluster.ids) 
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$AIW60.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'AIW60.pred', label = TRUE)
 
## check the proportion of cell types predicted in each cluster
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$predicted.id))
pr.t.lables <- as.data.frame(prop.table(table(seu.q$RNA_snn_res.0.2, seu.q$predicted.id)))
t.lables$Freq <- as.double(t.lables$Freq)


# try bar chart
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity")

# save ojbect with predicitons
saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Neurons2PredictionsSeu30092022.RDS")

Predict from Brain Bhahani


seu.q <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Neurons2LabelsSeu30092022.RDS")


# read in the reference dataset
# from Bhaduri midbrain and striatum
seu.r <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PublicData/Bhaduri_wholeBrain/Bhaduri_midbrain_striatum.RDS")
table(seu.r$cell_type)

      astrocyte        dividing     endothelial     interneuron       microglia          neuron 
            310             351             321               4              30            1596 
oligodendrocyte     radial glia 
            195             162 
table(seu.r$cell_class)

   dividing endothelial        glia   microglia      neuron 
        351         321         667          30        1600 
table(seu.r$cell_cluster)

      Astrocyte_4       Astrocyte_5       Dividing_11        Dividing_2        Dividing_3 
              211                99                10                71               103 
       Dividing_4       Dividing_42        Dividing_5           Endo_11           Endo_13 
               38                 1               128                28                 1 
          Endo_15            Endo_4            Endo_5            Endo_7            Endo_8 
               10               144                14                93                31 
GW14_Microglia_27     Interneuron_1    Interneuron_24     Interneuron_9      Microglia_10 
                4                 1                 2                 1                 9 
      Microglia_2       Microglia_8        Neuron_100          Neuron_2         Neuron_22 
                9                 8                 1                57                44 
        Neuron_37          Neuron_4          Neuron_5         Neuron_98          Oligo_11 
              104               249              1049                92                35 
          Oligo_2           Oligo_6           Oligo_8              RG_1             RG_37 
               58                83                19                80                 1 
             RG_4             RG_45              RG_6              RG_7 
               22                33                25                 1 
Idents(seu.r) <- "cell_cluster"

# find the reference anchors
anchors <- FindTransferAnchors(reference = seu.r, query = seu.q, dims = 1:25)
Performing PCA on the provided reference using 1841 features as input.
Projecting cell embeddings
Finding neighborhoods
Finding anchors
    Found 1051 anchors
Filtering anchors
    Retained 318 anchors
print("getting predictions")
[1] "getting predictions"
predictions <- TransferData(anchorset = anchors, refdata = seu.r$cell_cluster)
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Predicting cell labels
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Astrocyte_4  Dividing_3  Dividing_5      Endo_4      Endo_7      Endo_8    Neuron_2   Neuron_22 
       2105          24          20         987         346           4          32           1 
  Neuron_37    Neuron_4   Neuron_98    Oligo_11     Oligo_2        RG_1       RG_45        RG_6 
       3353        1070         866           2           5           6           1          62 
Idents(seu.q) <- 'predicted.id'
seu.q$Bha.mid.stri.pred <- Idents(seu.q)
print(table(seu.q$Bha.mid.stri.pred))

   Neuron_4   Neuron_37 Astrocyte_4   Neuron_98      Endo_4      Endo_7        RG_6        RG_1 
       1070        3353        2105         866         987         346          62           6 
 Dividing_3      Endo_8    Oligo_11    Neuron_2  Dividing_5     Oligo_2   Neuron_22       RG_45 
         24           4           2          32          20           5           1           1 
DimPlot(seu.q, group.by = 'Bha.mid.stri.pred')

DimPlot(seu.q, group.by = 'subgroups')


# do the predictions differ with the main cell type groups instead of the cluster in the reference data? 
Idents(seu.r) <- "cell_type"

# find the reference anchors
anchors <- FindTransferAnchors(reference = seu.r, query = seu.q, dims = 1:25)
Performing PCA on the provided reference using 1841 features as input.
Projecting cell embeddings
Finding neighborhoods
Finding anchors
    Found 1051 anchors
Filtering anchors
    Retained 318 anchors
print("getting predictions")
[1] "getting predictions"
predictions <- TransferData(anchorset = anchors, refdata = seu.r$cell_type)
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Predicting cell labels
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

      astrocyte        dividing     endothelial          neuron oligodendrocyte     radial glia 
           1294              34            1386            5606              53             511 
DimPlot(seu.q, group.by = 'predicted.id')


# good largest prediction is neurons. 

See the top predictions for each cluster in Neurons2 res 06

pred.table <- merge(df.top.AST23, df.top.aiw60, by = 'I', all = TRUE)
pred.table <- merge(pred.table, df.top.aiw120, by = 'I')
pred.table <- merge(pred.table, df.top.Bha, by = 'I')
Warning in merge.data.frame(pred.table, df.top.Bha, by = "I") :
  column names ‘Var1.x’, ‘Var2.x’, ‘Freq.x’, ‘Var1.y’, ‘Var2.y’, ‘Freq.y’ are duplicated in the result
pred.table
pred.table <- merge(df.top.AST23, df.top.aiw60, by = 'I', all = TRUE)
pred.table <- merge(pred.table, df.top.aiw120, by = 'I')
pred.table <- merge(pred.table, df.top.Bha, by = 'I')
Warning in merge.data.frame(pred.table, df.top.Bha, by = "I") :
  column names ‘Var1.x’, ‘Var2.x’, ‘Freq.x’, ‘Var1.y’, ‘Var2.y’, ‘Freq.y’ are duplicated in the result
pred.table

What cell types are predicted across the 3 references

0 - Neurons early , NPC, neurons excitatory 1 - Neurons early, NPC 2 - Neurons early, NPC, neurons excitatory some DA neurons 3 - Oligo, RG, 4 - Excitatory neurons, NPC, early neurons 5 - DA neurons, early DA neurons 6 - neurons immature NPC 7 - DA neurons 8 - RG, oligo, OPC, NPC 9 - Radial Glia 10 - NPC, neurons, oligo 11 - NPC, neurons, oligo

Find cluster markers and see how those would annotate

Idents(seu.q) <- 'RNA_snn_res.0.6'
ClusterMarkers <- FindAllMarkers(seu.q, only.pos = TRUE)

top5 <- ClusterMarkers %>% group_by(cluster) %>% top_n(n=5, wt = avg_log2FC)
DoHeatmap(seu.q, features = top5$gene, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')

write.csv(ClusterMarkers,"/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/Neurons1ClusterMarkers11.csv")

Cluster 0 has fewer markers. 2 and 5 have similar up reg markers 3 and 4 also overlap

Look at the cluster markers in cell type libraries for Neurons 2

library(enrichR)
db <- c('Allen_Brain_Atlas_up','Descartes_Cell_Types_and_Tissue_2021',
        'CellMarker_Augmented_2021','Azimuth_Cell_Types_2021')

# enrichr(genes, databases = NULL)
# cluster 0

N1.c0 <- ClusterMarkers %>% filter(cluster == 0 & avg_log2FC > 0)
genes <- N1.c0$gene

N1.c0.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c0.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c0.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c0.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c0.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c0.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c0.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

# cluster 1

N1.c1 <- ClusterMarkers %>% filter(cluster == 1 & avg_log2FC > 0)
genes <- N1.c1$gene

N1.c1.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c1.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c1.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c1.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c1.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c1.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c1.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c1.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c1.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4

# cluster 1; olfactory bulb, neural plate, maybe Radial Glia, 
N1.c2 <- ClusterMarkers %>% filter(cluster == 2 & avg_log2FC > 0)
genes <- N1.c2$gene

N1.c2.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c2.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c2.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c2.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c2.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c2.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c2.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c2.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c2.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4

# cluster 3

N1.c3 <- ClusterMarkers %>% filter(cluster == 3 & avg_log2FC > 0)
genes <- N1.c3$gene

N1.c3.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c3.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c3.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c3.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c3.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c3.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c3.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c3.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c3.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4

# cluster 4

N1.c4 <- ClusterMarkers %>% filter(cluster == 4 & avg_log2FC > 0)
genes <- N1.c4$gene

N1.c4.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c4.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c4.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c4.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c4.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c4.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c4.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c4.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c4.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4

# cluster 5

N1.c5 <- ClusterMarkers %>% filter(cluster == 5 & avg_log2FC > 0)
genes <- N1.c5$gene

N1.c5.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c5.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c5.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c5.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c5.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c5.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c5.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c5.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c5.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4

# cluster 6

N1.c6 <- ClusterMarkers %>% filter(cluster == 6 & avg_log2FC > 0)
genes <- N1.c6$gene

N1.c6.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c6.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c6.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c6.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c6.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c6.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c6.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c6.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c6.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4


# other clusters - change the cluster number
N1.c6 <- ClusterMarkers %>% filter(cluster == 11 & avg_log2FC > 0)
genes <- N1.c6$gene

N1.c6.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c6.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c6.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c6.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c6.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c6.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c6.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c6.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

N1.Er.genes.4 <- N1.c6.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4

cluster 0 - astrocyte, radial glia, microglia, striatum - very few genes in these terms cluster 1 - adrenal, thalmus, endothelial, astrocytes, neurons clusters 2 - neural plate, stratum, neurons, NPC, stem, astro,neuroendocrine cluster 3 - brain molecular layer, endothelial, astrocyte embryonic, cluster 4 - DG, striatum CA3, GABAergic neurons cluster 5 - DG, neurons, Glutamatergic neurons cluster 6 - neurons, astrocyte, microglia, GABAneurons cluster 7 - neurons, glut and gaba cluster 8 - astrocyte, endothelial, pericyte cluster 9 - epithelial, embryonic astrocytes, GABA neurons cluster 10 - epithelial cluster 11 - endothelial, immune cells T cells

Expression of markers genes in Neurons2


feature_list = c("MKI67","SOX2","POU5F1","DLX2","PAX6","SOX9","HES1","NES","RBFOX3","MAP2","NCAM1","CD24","GRIA2","GRIN2B","GABBR1","GAD1","GAD2","GABRA1","GABRB2","TH","ALDH1A1","LMX1B","NR4A2","CORIN","CALB1","KCNJ6","CXCR4","ITGA6","SLC1A3","CD44","AQP4","S100B", "PDGFRA","OLIG2","MBP","CLDN11","VIM","VCAM1")

DoHeatmap(seu.q, features = feature_list, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = feature_list) +RotatedAxis()

PD_poulin = c("TH","SLC6A3","SLC18A2","SOX6","NDNF","SNCG","ALDH1A1","CALB1","TACR2","SLC17A6","SLC32A1","OTX2","GRP","LPL","CCK","VIP")

DoHeatmap(seu.q, features = PD_poulin, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = PD_poulin)+RotatedAxis()

ealryNeur = c("DCX","NEUROD1","TBR1")
proliferation = c("PCNA","MKI67")
neuralstem = c("SOX2","NES","PAX6","MASH1")

feature_list <- c("DCX","NEUROD1","TBR1","PCNA","MKI67","SOX2","NES","PAX6","MASH1")
DoHeatmap(seu.q, features = feature_list, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = feature_list)+RotatedAxis()
# no proliferation marker expression  PCNA or MKI67
# cluster 4 DA neurons - shows early neuron marker and low PAX 4
# cluster 3 has higher SOX2 - neuroblast marker / NPC marker

mat_neuron = c("RBFOX3","SYP","DLG45","VAMP1","VAMP2","TUBB3","SYT1","BSN","HOMER1","SLC17A6") 
# NeuN is FOX3 - RBFOX3
# PSD95 also SP-90 or DLG4
# VGLUT2 is SLC17A6
DoHeatmap(seu.q, features = mat_neuron, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
# cluster 4 also show mature neuron markers
DotPlot(seu.q, features = mat_neuron)+RotatedAxis()
# excitatory neuron markers
ex = c("GRIA2","GRIA1","GRIA4","GRIN1","GRIN2B","GRIN2A","GRIN3A","GRIN3","GRIP1","CAMK2A")
DoHeatmap(seu.q, features = ex, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = ex)+RotatedAxis()
# inhibitory neuron markers
inh = c("GAD1","GAD2", "GAT1","PVALB","GABR2","GABR1","GBRR1","GABRB2","GABRB1","GABRB3","GABRA6","GABRA1","GABRA4","TRAK2")
DoHeatmap(seu.q, features = inh, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = inh)+RotatedAxis()
# cluster 4 is more excitatory than inhbitory but neither marker set has much expression 

### glia markers
microglia = c("PTPRC","AIF1","ADGRE1")  # ADGRE1 is a microglia marker F4/80, CD45 is PTPRC, gene name IBA1 is AIF1
astolgNPCpromicro = c("GFAP","S100B","SLC1A2","MBP","SOX10","SPP1","DCX","NEUROD1","TBR1","PCNA","MKI67","PTPRC","AIF1","ADGRE1")
# note GLT1 is EAAT2 which is SLC1A2 glutatmate transporter
# epithelial
epi = c("HES1","HES5","SOX2","SOX10","NES","CDH1","NOTCH1") # e-cadherin is CDH1

DoHeatmap(seu.q, features = astolgNPCpromicro, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = astolgNPCpromicro, group.by = 'RNA_snn_res.0.6')+RotatedAxis()
# cluster 4 is more excitatory than inhbitory but neither marker set has much expression 
DoHeatmap(seu.q, features = epi, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = epi, group.by = 'RNA_snn_res.0.6')+RotatedAxis()

# also add Radial glia marker overlap with Glia and Neurons

features <- c("PTPRC","AIF1","ADGRE1", "VIM", "TNC","PTPRZ1","FAM107A","HOPX","LIFR",
              "ITGB5","IL6ST")
DoHeatmap(seu.q, features = features, size=3, angle =90, group.bar.height = 0.02, group.by = 'RNA_snn_res.0.6')
DotPlot(seu.q, features = features, group.by = 'RNA_snn_res.0.6')+RotatedAxis()

Label the Neuron2 FACS population


Idents(seu.q) <- 'RNA_snn_res.0.6'
cluster.ids <- c("Neurons1","immatureNeurons1","Neurons2",
                 "Other","DAneurons1","DAneurons2","immatureNeurons2",
                 "DAneurons3","RG","immatureNeurons1","Epithelial","Endothelial")
unique(seu.q$RNA_snn_res.0.6)

names(cluster.ids) <- levels(seu.q)
seu.q <- RenameIdents(seu.q, cluster.ids)
seu.q$subgroups <- Idents(seu.q)

DimPlot(seu.q, reduction = "umap", label = TRUE, group.by = 'subgroups', repel = TRUE)


# label again with just numbering
# then I'll find markers in pairs to distinguish groups. 

Idents(seu.q) <- 'RNA_snn_res.0.6'
cluster.ids <- c("Neurons1","Neurons2","Neurons3",
                 "Other","DAneurons1","DAneurons2","Neurons4",
                 "DAneurons3","RG","Neurons2","Epithelial","Endothelial")
unique(seu.q$RNA_snn_res.0.6)

names(cluster.ids) <- levels(seu.q)
seu.q <- RenameIdents(seu.q, cluster.ids)
seu.q$number.groups <- Idents(seu.q)

DimPlot(seu.q, reduction = "umap", label = TRUE, group.by = 'number.groups', repel = TRUE)


saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Neurons2LabelsSeu30092022.RDS")

Find markers in pairs to go back and classify the subgroups. Will need to return to this for Neurons1 FACS

Neurons 5 and Neurons2 had similar markers and were merged Subset again


# faster to make a subset objects of only neurons and use find all markers

neuron.sub <- subset(seu.q, idents = c("Neurons1","Neurons2","Neurons3",
                                       "Neurons4"))

neuron.sub.markers <- FindAllMarkers(neuron.sub)

top5 <- neuron.sub.markers %>% group_by(cluster) %>% top_n(n=5, wt = avg_log2FC)
DoHeatmap(neuron.sub, features = top5$gene, size=3, angle =90, group.bar.height = 0.02)

DotPlot(neuron.sub, features = top5$gene) + RotatedAxis()


# neurons 5 was joined to Neurons 2
# cluster markers done again

# Neurons1 : MGP (targeting neural projections BMP signaling), HPD (excitatory and inibitory, could be cell adhesion or apoptosis), MSX1 (transcription factor BMP signaling, midbrain marker, developmental), CYP1B1 (redox homeostatis)   
# MGP, HPD, MSX1, CYP1B1

# there isn't a good proportion of cells expression any of the markers, Neurons2 has the best amount

# Neurons2: TFP12 serine protease melatonin conversion, PTN (cytokine signaling), LYgH (inhances nAChRs), S100A10 (modulates serotonin receptor), IFI27 (antiviral activity)
#TFP12,PTN, LY6H, S100A10, IFI27 

# Neurons3: SOX4, ASCL1 (neurogenesis),

# SOX4 is a marker of 3 but has high expression in 4 as well 

# Neurons4: PCAT4 (not noted in neurons), TPH1 (5HT synthesis), GK5 (neuronal maintainance), SST (somatostatin, GABA spike regulation), TTR (neural protective in AD)
# PCAT4, TPH1, GK5, SST, TTR

# markers to use

# Neurons1: MSX1, CYP1B1      
# Neurons2: LY6H, S100A10     
# Neurons3: SOX4, ASCL1 (Neurogenesis) Immature
# Neurons4: GK5, SST                         More mature



# Maybe neurons 1 and 2 could be merged

# lets see how the markers would look

neurons.1and2 <- FindMarkers(neuron.sub, ident.1 = c("Neurons1","Neurons2"),
                             ident.2 = c("Neurons3","Neurons4"))

top10 <- neurons.1and2 %>% top_n(n=10, wt = avg_log2FC)
ft.up <- rownames(top10) # up in Neurons1 and 3
top10 <- neurons.1and2 %>% top_n(n=-10, wt = avg_log2FC)
ft.down <- rownames(top10)
features <- c(ft.up,ft.down)

DoHeatmap(neuron.sub, features = features, size=3, angle =90, group.bar.height = 0.02)

DotPlot(neuron.sub, features = features) + RotatedAxis()

# all the markers were up regulated in neurons2 and not really neurons1
# I'll keep them separated

Use subgrouping and find cluster markers to look at neuronal subtypes.


# faster to make a subset objects of only neurons and use find all markers

neuron.sub <- subset(seu.q, idents = c("DAneurons1","DAneurons2","DAneurons3"))

neuron.sub.markers <- FindAllMarkers(neuron.sub)

top5 <- neuron.sub.markers %>% group_by(cluster) %>% top_n(n=5, wt = avg_log2FC)
DoHeatmap(neuron.sub, features = top5$gene, size=3, angle =90, group.bar.height = 0.02)

DotPlot(neuron.sub, features = top5$gene) + RotatedAxis()

# markers are much clearer for the DA neuron subgroups

# DA neurons 1: WIF1, CYP1B1, IGFBP3, HPD, WFIKKN2
# WIF1 (secreted WNT inhibitor, promotes regeneration), CYP1B1 (redox homeostatis), IGFBP3 (prolactin secretion regulation hypothalmus), HPD (neuro protective), WFIKKN2 (Receptor for TNC)
# DA neurons2: CDH7, RUNX1T1, ASCL1, DLK1, MEG3
# CDH7 (neuro circuitry development, SEMA), RUNX1T1 (neuronal differentiation), ASCL1 (neuronal differentiation), DLK1 (neural differentation), MEG3 (neural homeostatis)  
# DA neurons3: PCAT4, NEUROD1, NCKAP5, GK5, SST
# PCAT4 (dendritic growth), NEUROD1 (neural differentation), NCKAP5 (Excitory neurons), GK5 (TH ), SST (regualates spike times)

# DA neurons1: CYP1B1, IGFBP3
# DA neurons2: RUNX1T1, ASCL1
# DA neurons3: NEUROD1, NCKAP5

Name the Neurons2 FACS population with the Neuron subtype latter.


Idents(seu.q) <- 'RNA_snn_res.0.6'
cluster.ids <- c("Neurons-MSX1","Neurons-LY6H","Neurons-ASCL1",
                 "Other","DAneurons-CYP1B1","DAneurons-ASCL1","Neurons-GK5",
                 "DAneurons-NEUROD1","RG","Neurons-LY6H","Epithelial","Endothelial")

unique(seu.q$RNA_snn_res.0.6)

names(cluster.ids) <- levels(seu.q)
seu.q <- RenameIdents(seu.q, cluster.ids)
seu.q$cellsubgroups <- Idents(seu.q)

DimPlot(seu.q, reduction = "umap", label = TRUE, group.by = 'cellsubgroups', repel = TRUE)
preduction summary  Cell_Types

0 neurons Neurons 1 NPC/oligo/astro/neurons/RG Neurons 2 neurons Neurons 3 NPC/RG/Astro Neurons 4 RG/endo RG 5 DA neurons Neurons 6 Neurons Neurons 7 DA neurons Neurons 8 RG/endo Endothelial 9 RG/astro Astro 10 opc/npc/astro/neurons Neurons 11 neurons/dividing/RG Neurons

Clustering higher res res 1.2 0 Neurons 1 Neurons 2 Neurons 3 Astro/RG/Neurons 4 RG/Astro/Neurons 5 RG/Neurons/NPC 6 RG/NPC/Endo 7 Neurons DA 8 Neurons 9 Neurons DA 10 Neurons DA 11 RG/Endo 12 RG/Astro 13 RG/Astro/Neurons 14 Neurons/RG


Idents(seu.q) <- 'RNA_snn_res.1.2'
# highlight the DA neurons
cluster.ids <- c("Neurons","Neurons","NPC",
                 "Neurons","Neurons","Neurons",
                 "Neurons DA","Neurons","Neurons DA",
                 "Neurons DA", "Neurons DA","Endothelial",
                 "RG/Astro","RG/Astro/Neurons","Neurons/RG")
cluster.ids <- c("Neurons","Neurons","Neurons",
                 "Neurons","Neurons","NPC",
                 "Neurons","Neurons","Neurons",
                 "Neurons", "Neurons","Endothelial",
                 "Astrocytes","Radial Glia","Radial Glia")

names(cluster.ids) <- levels(seu.q)
seu.q <- RenameIdents(seu.q, cluster.ids)
seu.q$Cell_Types <- Idents(seu.q)

DimPlot(seu.q, reduction = "umap", label = TRUE, group.by = 'Cell_Types', repel = TRUE)

#DimPlot(seu.q, reduction = "umap", label = TRUE, group.by = 'RNA_snn_res.1.2', repel = TRUE)

#clustree(seu.q)

# save the Neurons2 with labels

saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Neurons2LabelsSeu30092022.RDS")

FACS population Glia1 (should be astrocytes)

# explore filtering
seu <- Glia1
seu
# 
VlnPlot(seu, pt.size = 0.10, features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 3)

VlnPlot(seu, pt.size = 0.10, features = c("nFeature_RNA"), y.max = 1000)
VlnPlot(seu, pt.size = 0.10, features = c("nFeature_RNA"), y.max = 500)
VlnPlot(seu, pt.size = 0.10, features = c("nCount_RNA"), y.max = 2000)

# filter more cells

seu.ft <- subset(seu, subset = nFeature_RNA > 300 & nCount_RNA > 500 & nCount_RNA < 10000) 
seu.ft

# still a lot of cells 47295
# will likely remove a lot more with the doublet finder

saveRDS(seu.ft, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia1AstroSeu01102022.RDS")

seu.ft <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia1AstroSeu01102022.RDS")

seu.ft <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia1AstroSeu01102022.RDS")

Doublet finder


suppressMessages(require(DoubletFinder))

# filtering out MALAT1 and mitochondrial genes

seu.ft <- seu.ft[!grepl("MALAT1", rownames(seu.ft)), ]
seu.ft <- seu.ft[!grepl("^MT-", rownames(seu.ft)), ]

# like in the tutorial I'm following MALAT1 is the top most expressed gene.  The top genes are a lot of MT and Ribosomal genes

seu.ft[["percent.rb"]] <- PercentageFeatureSet(seu.ft, pattern = "^RP")

# down sample there are too many cells to run doublet finder
seu.sub <- subset(seu.ft, downsample = 20000)

seu.d = NormalizeData(seu.sub)
seu.d = FindVariableFeatures(seu.d, verbose = F)
seu.d = ScaleData(seu.d, vars.to.regress = c("nFeature_RNA", "percent.mt"),
    verbose = F)
seu.d = RunPCA(seu.d, verbose = F, npcs = 15)
seu.d = RunUMAP(seu.d, dims = 1:10, verbose = F)

nExp <- round(ncol(seu.d) * 0.15)  # expect more doublets because there is a lot more cells
seu.d <- doubletFinder_v3(seu.d, pN = 0.25, pK = 0.09, nExp = nExp, PCs = 1:10)
# the memory limit is reached here - I could run on compute canada
# For now I'll downsample
# this works

# name of the DF prediction can change, so extract the correct column name.
DF.name = colnames(seu.d@meta.data)[grepl("DF.classification", colnames(seu.d@meta.data))]


cowplot::plot_grid(ncol = 2, DimPlot(seu.d, group.by = "orig.ident") + NoAxes(),
    DimPlot(seu.d, group.by = DF.name) + NoAxes())

VlnPlot(seu.d, features = "nFeature_RNA", group.by = DF.name, pt.size = 0.1)

Remove the doublet cells

seu.d <- seu.d[, seu.d@meta.data[, DF.name]== "Singlet"]
dim(seu.d)
dim(seu.sub)

# 20000 pre filter
# creates the expected percentage

Repeat workflow with doublet removed data and find clusters for

seu <- NormalizeData(seu.d, normalization.method = "LogNormalize", scale.factor = 10000)
seu <- FindVariableFeatures(seu, selection.method = "vst", nfeatures = 2000)
seu <- ScaleData(seu)
seu <- RunPCA(seu)
seu <- RunUMAP(seu, reduction = "pca", n.neighbors = 43, dims = 1:30)
DimPlot(seu, reduction = "umap")

seu.q <- FindNeighbors(seu, dims = 1:25, k.param = 43)
seu.q <- FindClusters(seu.q, resolution = c(0,0.2,0.4,0.6))
seu.q <- FindClusters(seu.q, resolution = c(0,0.05,0.1,0.8))
library(clustree)
clustree(seu.q)
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.05')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.1')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.2')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.4')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.6')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.8')

Look at some expression markers in a feature plot

# genes reported up in Astrocytes
FeaturePlot(seu.q, features = c("GFAP","S100B","AQP4","SLC1A3","GJA1",
                                "APOE","TEAD1","GSTA4","SOX9",
                                "VIM","HMG20A","ALDH1L1"))
# almost no GFAP expression and lots of S100B everywhere

Predict cell types



# SNCA and control midbrain organoids 165 days in culture
MBO <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/AST23_BrainComm/MBOclusters_names29072021.rds")

# Midbrain  AIW002 120 days in culture
AIWMBO <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/AIWtrio120days/MOintegratedClusterK123res0.8.names_nov16_2021")

# Midbrain AIW002 60 days in culture

AIW60 <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/AIWtrio60days/AWI002ParkinKOPinkKO60days_labels_14052022.rds")


#first predict with the MBO data
Idents(MBO) <- "cluster_labels"
DefaultAssay(MBO) <- "RNA"

# find the reference anchors
print("finding reference anchors")
anchors <- FindTransferAnchors(reference = MBO ,query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = MBO$cluster_labels)
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$MBOAST23.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'MBOAST23.pred', label = TRUE)
 
## check the proportion of cell types predicted in each cluster
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.8, seu.q$MBOAST23.pred))
t.lables$Freq <- as.double(t.lables$Freq)

# try bar chart
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity")

# clusters don't break up by the predicted cell types

############ another predictions now using the AIW organoids

Idents(AIWMBO) <- "res08names"
DefaultAssay(AIWMBO) <- "RNA"

anchors <- FindTransferAnchors(reference = AIWMBO ,query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = AIWMBO$res08names)
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$MBOAIW.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'MBOAIW.pred', label = TRUE)
 
## check the proportion of cell types predicted in each cluster
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.8, seu.q$MBOAIW.pred))
t.lables$Freq <- as.double(t.lables$Freq)

# try bar chart
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity")

# the predicted cell types make more sense from the AIW002 organoid
# now predict with the AIW002 60 days organoid

Idents(AIW60) <- "cluster.ids"
DefaultAssay(AIW60) <- "RNA"

anchors <- FindTransferAnchors(reference = AIW60, query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = AIW60$cluster.ids) 
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$AIW60.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'AIW60.pred', label = TRUE)
 
## check the proportion of cell types predicted in each cluster
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.8, seu.q$AIW60.pred))
t.lables$Freq <- as.double(t.lables$Freq)

# try bar chart
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity")

# save ojbect with predicitons
saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia1PredictionsSeu01102022.RDS")

Predict with the brain scRNAseq

seu.r <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PublicData/Bhaduri_wholeBrain/Bhaduri_midbrain_striatum.RDS")

Idents(seu.r) <- "cell_cluster"

# find the reference anchors
anchors <- FindTransferAnchors(reference = seu.r, query = seu.q, dims = 1:25)
Performing PCA on the provided reference using 1841 features as input.
Projecting cell embeddings
Finding neighborhoods
Finding anchors
    Found 752 anchors
Filtering anchors
    Retained 108 anchors
print("getting predictions")
[1] "getting predictions"
predictions <- TransferData(anchorset = anchors, refdata = seu.r$cell_cluster)
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Predicting cell labels
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Astrocyte_4      Endo_4   Neuron_98        RG_1 
       7791        3019           2        9188 
Idents(seu.q) <- 'predicted.id'
seu.q$Bha.mid.stri.pred <- Idents(seu.q)
print(table(seu.q$Bha.mid.stri.pred))

Astrocyte_4      Endo_4        RG_1   Neuron_98 
       7791        3019        9188           2 
DimPlot(seu.q, group.by = 'Bha.mid.stri.pred')

DimPlot(seu.q, group.by = 'subgroups')


# do the predictions differ with the main cell type groups instead of the cluster in the reference data? 
Idents(seu.r) <- "cell_type"

# find the reference anchors
anchors <- FindTransferAnchors(reference = seu.r, query = seu.q, dims = 1:25)
Performing PCA on the provided reference using 1841 features as input.
Projecting cell embeddings
Finding neighborhoods
Finding anchors
    Found 752 anchors
Filtering anchors
    Retained 108 anchors
print("getting predictions")
[1] "getting predictions"
predictions <- TransferData(anchorset = anchors, refdata = seu.r$cell_type)
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Predicting cell labels
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

  astrocyte endothelial      neuron radial glia 
       3747        7012        2152        7089 
DimPlot(seu.q, group.by = 'predicted.id')


# AIW002 120 days predictions
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$MBOAIW.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.AIW120 <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.aiw120 <- top.pred.celltype.AIW120[order(top.pred.celltype.AIW120$Var1,-top.pred.celltype.AIW120$Freq),]
row.names(df.top.aiw120) <- NULL
df.top.aiw120$I <- row.names(df.top.aiw120)

# AIW002 60 days predictions
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$AIW60.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.AIW60 <-as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.aiw60 <- top.pred.celltype.AIW60[order(top.pred.celltype.AIW60$Var1,-top.pred.celltype.AIW60$Freq),]
row.names(df.top.aiw60) <- NULL
df.top.aiw60$I <- row.names(df.top.aiw60)


# AST23 165 days predictions
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$MBOAST23.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.AST23 <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.AST23 <- top.pred.celltype.AST23[order(top.pred.celltype.AST23$Var1,-top.pred.celltype.AST23$Freq),]
row.names(df.top.AST23) <- NULL
df.top.AST23$I <- row.names(df.top.AST23)

### add in the prediction from brain data Bhaduri midbrain and striatum
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$Bha.mid.stri.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.Bha <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.Bha <- top.pred.celltype.Bha[order(top.pred.celltype.Bha$Var1,-top.pred.celltype.Bha$Freq),]
row.names(df.top.Bha) <- NULL
df.top.Bha$I <- row.names(df.top.Bha)

## these are calculated below
### add in the prediction from brain whole brain data Bhaduri midbrain down sampled
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$Bha))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.Bha1 <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.Bha1 <- top.pred.celltype.Bha1[order(top.pred.celltype.Bha$Var1,-top.pred.celltype.Bha$Freq),]
row.names(df.top.Bha1) <- NULL
df.top.Bha1$I <- row.names(df.top.Bha1)

pred.table <- merge(df.top.AST23, df.top.aiw60, by = 'I', all = TRUE)
pred.table <- merge(pred.table, df.top.aiw120, by = 'I')
pred.table <- merge(pred.table, df.top.Bha, by = 'I')
Warning in merge.data.frame(pred.table, df.top.Bha, by = "I") :
  column names ‘Var1.x’, ‘Var2.x’, ‘Freq.x’, ‘Var1.y’, ‘Var2.y’, ‘Freq.y’ are duplicated in the result
pred.table <- merge(pred.table, df.top.Bha1, by = 'I')
Warning in merge.data.frame(pred.table, df.top.Bha1, by = "I") :
  column names ‘Var1.x’, ‘Var2.x’, ‘Freq.x’, ‘Var1.y’, ‘Var2.y’, ‘Freq.y’ are duplicated in the result
pred.table
NA

These predictions are not good. There are several astrocyte markers by expression levels. Everything is predicted as Radial glia or oligo dendrocytes

Try to predict with the whole brain and see if it’s different

Idents(seu.q) <- 'predicted.id'
seu.q$Bha <- Idents(seu.q)
print(table(seu.q$Bha))

          Oligo_9            Endo_1 GW20_Astrocyte_39       Astrocyte_4            Endo_2       Astrocyte_1 
              692               415              1312              8401              4497              2308 
      Astrocyte_2            Endo_3         Neuron_37        Dividing_5            IPC_34            IPC_29 
              159              1621               521                24                35                 1 
   GW18_2_45Oligo        Dividing_1           Oligo_8  GW19_2_45Outlier           Oligo_6 
                2                 5                 4                 2                 1 
DimPlot(seu.q, group.by = 'Bha')

DimPlot(seu.q, group.by = 'subgroups')

Try to predict with the astrocyte Kamath data


astro.ref <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/Macosko_Data/PD_astro.Rds")
# need to make PCA and UMAP
astro.ref <- NormalizeData(astro.ref)
astro.ref <- FindVariableFeatures(astro.ref, selection.method = "vst", nfeatures = 2000)
astro.ref <- ScaleData(astro.ref)
astro.ref <- RunPCA(astro.ref)
astro.ref <- RunUMAP(astro.ref, reduction = "pca", n.neighbors = 205, dims = 1:25)

colnames(astro.ref@meta.data)


Idents(astro.ref) <- "Cell_Subtype"
DefaultAssay(astro.ref) <- "RNA"

# find the reference anchors
print("finding reference anchors")
anchors <- FindTransferAnchors(reference = astro.ref ,query = seu.q, dims = 1:20)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = astro.ref$Cell_Subtype, k.weight = 10)
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$astro.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'astro.pred', label = TRUE)
table(seu.q$astro.pred)

seu.q$predicted.id <- ifelse(seu.q$prediction.score.max > 0.95, seu.q$predicted.id, NA)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
seu.q$astro.pred.thresh <- Idents(seu.q)
DimPlot(seu.q, group.by = 'astro.pred.thresh', label = TRUE)
table(seu.q$astro.pred.thresh)

# 19986 Astro_VIM_TNFSRF12A no threshold      Astro_GLYATL2 14
# 8376 Astro_VIM_TNFSRF12A   with 95% threshold


t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$astro.pred.thresh))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 
top.pred.astro <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.astro <- top.pred.astro[order(top.pred.astro$Var1,-top.pred.astro$Freq),]
row.names(df.top.astro) <- NULL


t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$astro.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 
top.pred.astro <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.astro <- top.pred.astro[order(top.pred.astro$Var1,-top.pred.astro$Freq),]
row.names(df.top.astro) <- NULL

Possible predicted in other clusters

clustree(seu.q)

Make the prediction table for high resolution Res 0.8 12 clusters

# AIW002 120 days predictions
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.8, seu.q$MBOAIW.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.AIW120 <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.aiw120 <- top.pred.celltype.AIW120[order(top.pred.celltype.AIW120$Var1,-top.pred.celltype.AIW120$Freq),]
row.names(df.top.aiw120) <- NULL
df.top.aiw120$I <- row.names(df.top.aiw120)

# AIW002 60 days predictions
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.8, seu.q$AIW60.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.AIW60 <-as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.aiw60 <- top.pred.celltype.AIW60[order(top.pred.celltype.AIW60$Var1,-top.pred.celltype.AIW60$Freq),]
row.names(df.top.aiw60) <- NULL
df.top.aiw60$I <- row.names(df.top.aiw60)


# AST23 165 days predictions
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.8, seu.q$MBOAST23.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.AST23 <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.AST23 <- top.pred.celltype.AST23[order(top.pred.celltype.AST23$Var1,-top.pred.celltype.AST23$Freq),]
row.names(df.top.AST23) <- NULL
df.top.AST23$I <- row.names(df.top.AST23)

### add in the prediction from brain data Bhaduri midbrain and striatum
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.8, seu.q$Bha.mid.stri.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.Bha <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.Bha <- top.pred.celltype.Bha[order(top.pred.celltype.Bha$Var1,-top.pred.celltype.Bha$Freq),]
row.names(df.top.Bha) <- NULL
df.top.Bha$I <- row.names(df.top.Bha)

## these are calculated below
### add in the prediction from brain whole brain data Bhaduri midbrain down sampled
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.8, seu.q$Bha))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.Bha1 <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.Bha1 <- top.pred.celltype.Bha1[order(top.pred.celltype.Bha$Var1,-top.pred.celltype.Bha$Freq),]
row.names(df.top.Bha1) <- NULL
df.top.Bha1$I <- row.names(df.top.Bha1)

pred.table <- merge(df.top.AST23, df.top.aiw60, by = 'I', all = TRUE)
pred.table <- merge(pred.table, df.top.aiw120, by = 'I')
pred.table <- merge(pred.table, df.top.Bha, by = 'I')
Warning in merge.data.frame(pred.table, df.top.Bha, by = "I") :
  column names ‘Var1.x’, ‘Var2.x’, ‘Freq.x’, ‘Var1.y’, ‘Var2.y’, ‘Freq.y’ are duplicated in the result
pred.table <- merge(pred.table, df.top.Bha1, by = 'I')
Warning in merge.data.frame(pred.table, df.top.Bha1, by = "I") :
  column names ‘Var1.x’, ‘Var2.x’, ‘Freq.x’, ‘Var1.y’, ‘Var2.y’, ‘Freq.y’ are duplicated in the result
pred.table
NA

Look at cluster markers


Idents(seu.q) <- 'RNA_snn_res.0.2'
ClusterMarkers <- FindAllMarkers(seu.q, only.pos = TRUE)

top5 <- ClusterMarkers %>% group_by(cluster) %>% top_n(n=5, wt = avg_log2FC)
DoHeatmap(seu.q, features = top5$gene, size=3, angle =90, group.bar.height = 0.02)

write.csv(ClusterMarkers,"/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/Glia1AstrocytesClusterMarkers_new.csv")

# for the res 0.6 the largers groups 0 and 1 don't have great markers and none of the markers are really very good.  
# I'll rerun with res 0.2
unique(seu.q$RNA_snn_res.0.2)

# still not much better

Check cell type markers with EnrichR


library(enrichR)

setEnrichrSite("Enrichr") # Human genes
# list of all the databases

# libaries with cell types

db <- c('Allen_Brain_Atlas_up','Descartes_Cell_Types_and_Tissue_2021',
        'CellMarker_Augmented_2021','Azimuth_Cell_Types_2021')

# enrichr(genes, databases = NULL)

#I'll run the clusters one at a time

N1.c0 <- ClusterMarkers %>% filter(cluster == 5 & avg_log2FC > 0)
genes <- N1.c0$gene

N1.c0.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c0.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c0.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c0.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c0.Er[[4]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")

N1.Er.genes.1 <- N1.c0.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c0.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c0.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3


N1.Er.genes.4 <- N1.c0.Er[[4]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.4



# cluster 0 - Cell type marker library - Brain astrocyte top hit and embryonic astrocytes
# gene list in term: brain astrocyte    EFEMP1;NFIA;LIX1;PSAP;KIF21A;S100B;CRYAB;DKK3
# embryo astrocytes SOX2;BEX1;HMGCS1;PTPRZ1;LIX1;S100B;DKK3;ITM2C

# cluster 1 - stem cell pericyte (brain), stelate, astrocyte

# cluster 2 - hypothalmus, endothelial cells, macrophage
# endothelial CSTB;PRELID1;MT1X;CRIP2;RHOC;TMEM141;MT2A;RPS28;CCDC85B;EIF3I;RBP1;ID1;C4ORF3;ID3;PCBD1;MSX1;PPIC

# cluster 3 - smooth muscle cells

# cluster 4 - NK cells, fibroblasts
# NK cells ITGB1;RAB5C;GSTP1;PDCD5;EEF1B2;TGOLN2;SDCBP;MT2A;LDHA;SNRPD2;YWHAQ;ZNF326;TMSB10;CCDC50
# fibroblasts   COL3A1;CALD1;COL6A3

# cluster 5 - endothelial cells, NK cells, CD8+

# cluster 6 - stromal cells eurythroblasts, none-neuronal, oligo

# reran and now there are only 5 clusters
# repeat checking

Cluster 0 - astrocytes Cluster 1 - pericyte astrocyte (weak still) Cluster 2 - endothelial Cluster 3 - smooth muscle Cluster 4 - NK/fibroblast Cluster 5 - endothelial Cluster 6 - non- neuronal


VlnPlot(seu.q, features = c("CD44","ITGB1","S100B"), group.by = 'orig.ident')
VlnPlot(seu.ft, features = c("CD44","ITGB1","S100B"), group.by = 'orig.ident')

Check expression of known markers


Idents(seu.q) <- 'RNA_snn_res.0.2'

feature_list = c("MKI67","SOX2","POU5F1","DLX2","PAX6","SOX9","HES1","NES","RBFOX3","MAP2","NCAM1","CD24","GRIA2","GRIN2B","GABBR1","GAD1","GAD2","GABRA1","GABRB2","TH","ALDH1A1","LMX1B","NR4A2","CORIN","CALB1","KCNJ6","CXCR4","ITGA6","SLC1A3","CD44","AQP4","S100B", "PDGFRA","OLIG2","MBP","CLDN11","VIM","VCAM1")

DoHeatmap(seu.q, features = feature_list, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = feature_list) +RotatedAxis()

PD_poulin = c("TH","SLC6A3","SLC18A2","SOX6","NDNF","SNCG","ALDH1A1","CALB1","TACR2","SLC17A6","SLC32A1","OTX2","GRP","LPL","CCK","VIP")

DoHeatmap(seu.q, features = PD_poulin, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = PD_poulin)+RotatedAxis()

ealryNeur = c("DCX","NEUROD1","TBR1")
proliferation = c("PCNA","MKI67")
neuralstem = c("SOX2","NES","PAX6","MASH1")

feature_list <- c("DCX","NEUROD1","TBR1","PCNA","MKI67","SOX2","NES","PAX6","MASH1")
DoHeatmap(seu.q, features = feature_list, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = feature_list)+RotatedAxis()


mat_neuron = c("RBFOX3","SYP","DLG45","VAMP1","VAMP2","TUBB3","SYT1","BSN","HOMER1","SLC17A6") 
# NeuN is FOX3 - RBFOX3
# PSD95 also SP-90 or DLG4
# VGLUT2 is SLC17A6
DoHeatmap(seu.q, features = mat_neuron, size=3, angle =90, group.bar.height = 0.02)
# cluster 4 also show mature neuron markers
DotPlot(seu.q, features = mat_neuron)+RotatedAxis()
# excitatory neuron markers
ex = c("GRIA2","GRIA1","GRIA4","GRIN1","GRIN2B","GRIN2A","GRIN3A","GRIN3","GRIP1","CAMK2A")
DoHeatmap(seu.q, features = ex, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = ex)+RotatedAxis()
# inhibitory neuron markers
inh = c("GAD1","GAD2", "GAT1","PVALB","GABR2","GABR1","GBRR1","GABRB2","GABRB1","GABRB3","GABRA6","GABRA1","GABRA4","TRAK2")
DoHeatmap(seu.q, features = inh, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = inh)+RotatedAxis()
# cluster 4 is more excitatory than inhbitory but neither marker set has much expression 

### glia markers
microglia = c("PTPRC","AIF1","ADGRE1")  # ADGRE1 is a microglia marker F4/80, CD45 is PTPRC, gene name IBA1 is AIF1
astolgNPCpromicro = c("GFAP","S100B","SLC1A2","MBP","SOX10","SPP1","DCX","NEUROD1","TBR1","PCNA","MKI67","PTPRC","AIF1","ADGRE1")
# note GLT1 is EAAT2 which is SLC1A2 glutatmate transporter
# epithelial
epi = c("HES1","HES5","SOX2","SOX10","NES","CDH1","NOTCH1") # e-cadherin is CDH1

DoHeatmap(seu.q, features = astolgNPCpromicro, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = astolgNPCpromicro)+RotatedAxis()
# cluster 4 is more excitatory than inhbitory but neither marker set has much expression 
DoHeatmap(seu.q, features = epi, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = epi)+RotatedAxis()

# also add Radial glia marker overlap with Glia and Neurons

features <- c("PTPRC","AIF1","ADGRE1", "VIM", "TNC","PTPRZ1","FAM107A","HOPX","LIFR",
              "ITGB5","IL6ST")
DoHeatmap(seu.q, features = features, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = features)+RotatedAxis()

No TH expression

clusters 5 VIM highest, S100 B Cluster 4 Cluster 3 has some cells with high OTX2, NES indicates NPC/Precursors Cluster 2 has some SOX2 and PAX6 indicates NPC, VAMP2 indicating neurons, S100B highest and most - indicates astrocytes, also MBP indicates oligos Cluster 1 Cluster 0

Lable the clusters


Idents(seu.q) <- 'RNA_snn_res.0.2'

#seu.q <- BuildClusterTree(seu.q, reorder = TRUE, reorder.numeric = TRUE)
unique(seu.q$RNA_snn_res.0.2)

cluster.ids <- c("Astrocytes1","Astrocytes2","Precursors","RG1","RG2","Endothelial")

names(cluster.ids) <- levels(seu.q)
seu.q <- RenameIdents(seu.q, cluster.ids)
seu.q$subgroups <- Idents(seu.q)

#DimPlot(seu.q, group.by = 'RNA_snn_res.0.2', label = TRUE)
DimPlot(seu.q, reduction = "umap", label = TRUE, group.by = 'subgroups', repel = TRUE)

# something weird is going on in the order

#saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia1LabledSeu301102022.RDS")

Compare the Astrocyte groups and get some markers for sub groups



astro.sub.markers <- FindMarkers(seu.q, ident.1 = "Astrocytes1", ident.2 = "Astrocytes2", only.pos = FALSE)
#top5 <- astro.sub.markers %>% top_n(n=5, wt = avg_log2FC)

DoHeatmap(seu.q, features = c("PLCG2","PTPRZ1","SNHG25","VCAN","LUM","DCN","S1004A"), size=3, angle =90, group.bar.height = 0.02)

astro2 <- rownames(astro.sub.markers %>% filter(avg_log2FC < 0.05))

DotPlot(seu.q, features = c("PLCG2","PTPRZ1","SNHG25","VCAN","LUM","DCN","S1004A")) + RotatedAxis()

DoHeatmap(seu.q, features = astro2[1:15], size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = astro2[1:15]) +RotatedAxis()


# radial glia subtyping
Idents(seu.q) <- ('subgroups')
rg.sub.markers <- FindMarkers(seu.q, ident.1 = "RG1", ident.2 = "RG2", only.pos = FALSE)
top5.up <- rg.sub.markers %>% top_n(n=10, wt = avg_log2FC)
top5.down <- rg.sub.markers %>% top_n(n=-10, wt = avg_log2FC)
ft <- rownames(top5.up)

DoHeatmap(seu.q, features = ft, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = ft) + RotatedAxis()


ft <- rownames(top5.down)

DoHeatmap(seu.q, features = ft, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = ft) + RotatedAxis()

npc.markers <- FindMarkers(seu.q, ident.1 = "Precursors", ident.2 = c("Astrocytes2","Astrocytes1"), only.pos = FALSE)
top10.npc <- npc.markers %>% top_n(n=10, wt = avg_log2FC)
npc.markers <- npc.markers %>% filter(avg_log2FC > 0)
dim(npc.markers)

ft <- rownames(top10.npc)
# consider naming precursors as astrocytes3
DoHeatmap(seu.q, features = ft, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = ft) + RotatedAxis()


npc.markers.rg <- FindMarkers(seu.q, ident.1 = "Precursors", ident.2 = c("RG2","RG1"), only.pos = TRUE)
top10.npc <- npc.markers.rg %>% top_n(n=10, wt = avg_log2FC)

ft <- rownames(top10.npc)
# consider naming precursors as astrocytes3
DoHeatmap(seu.q, features = ft, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = ft) + RotatedAxis()

## these have more differences from RG than Astrocytes

Add subtype gene ids


DimPlot(seu.q, group.by = 'RNA_snn_res.0.2')

cluster.ids <- c("Astrocytes-PLCG2","Astrocytes-DNC","Astrocytes-IGFBP2",
                 "RG1-CDKN1C","RG2-TYRP1","Endothelial")
#cluster.ids <- c("Astrocytes1","Astrocytes2","Precursors(Astrocytes)","RG1","RG2","Endothelial")

names(cluster.ids) <- levels(seu.q)
seu.q <- RenameIdents(seu.q, cluster.ids)
seu.q$Cell_types <- Idents(seu.q)

DimPlot(seu.q, reduction = "umap", label = TRUE, group.by = 'Cell_types', repel = TRUE)


saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia1LabledSeu301102022.RDS")

# label with main cell type groups 

DimPlot(seu.q, group.by = 'RNA_snn_res.0.2')

cluster.ids <- c("Astrocytes","Astrocytes","Astrocytes",
                 "RG","RG","Endothelial")
#cluster.ids <- c("Astrocytes1","Astrocytes2","Precursors(Astrocytes)","RG1","RG2","Endothelial")

names(cluster.ids) <- levels(seu.q)
seu.q <- RenameIdents(seu.q, cluster.ids)
seu.q$Cell_Type <- Idents(seu.q)

DimPlot(seu.q, reduction = "umap", label = TRUE, group.by = 'Cell_Type', repel = TRUE)


saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia1LabledSeu301102022.RDS")

Label main cell types Res 0.8 predicitons 0 astro 1 Endo/RG/Astro 2 Astrocyte 3 RG/Endo/Astro 4 Astro 5 Astro 6 Epithela, endo, astro, RG 7 Astro 8 Astro 9 Astro/RG/Endo 10 Astro/RG 11 Astro/Neurons 12 Endo/RG.


#DimPlot(seu.q, group.by = 'RNA_snn_res.0.8')
Idents(seu.q) <- 'RNA_snn_res.0.8'

cluster.ids <- c("Astrocytes","Astrocytes-Endo-RG","Astrocytes",
                 "RG-Endo-Astro","Astro","Astro","Epi-Endo-Astro-RG",
                 "Astro","Astro","Astro-RG-Endo","Astro-RG","Astro-Neurons","Endo-RG")

cluster.ids <- c("Astrocytes","Astrocytes","Astrocytes",
                 "Astrocytes","Astrocytes","Astrocytes","Endothelial",
                 "Astrocytes","Astrocytes","Radial Glia","Radial Glia","Astrocytes","Endothelial")

names(cluster.ids) <- levels(seu.q)
seu.q <- RenameIdents(seu.q, cluster.ids)
seu.q$Cell_Type <- Idents(seu.q)

DimPlot(seu.q, reduction = "umap", label = TRUE, group.by = 'Cell_Type', repel = TRUE)



saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia1LabledSeu301102022.RDS")
table(seu.q$Cell_Type)

 Astrocytes          RG Endothelial Radial Glia 
      16068        2955         506         471 

Quick check the Glial2


# explore filtering
seu <- Glia2
seu
# 
VlnPlot(seu, pt.size = 0.10, features = c("nFeature_RNA", "nCount_RNA", "percent.mt"), ncol = 3)

VlnPlot(seu, pt.size = 0.10, features = c("nFeature_RNA"), y.max = 1000)
VlnPlot(seu, pt.size = 0.10, features = c("nFeature_RNA"), y.max = 500)
VlnPlot(seu, pt.size = 0.10, features = c("nCount_RNA"), y.max = 2000)

# filter more cells

seu.ft <- subset(seu, subset = nFeature_RNA > 250 & nCount_RNA > 250 & nCount_RNA < 10000) 
seu.ft

VlnPlot(seu.ft, pt.size = 0.10, features = c("nFeature_RNA"), y.max = 2000)

VlnPlot(seu.ft.glia, features = c("CD44","S100B","ITGB1"))
VlnPlot(seu.ft, features = c("CD44","S100B","ITGB1"), group.by = 'orig.ident')
# both glia populations are similar

Levels seem similar in Glia1 and Glia2

Remove doublets and start to process Glia 2


suppressMessages(require(DoubletFinder))

# filtering out MALAT1 and mitochondrial genes

seu.ft <- seu.ft[!grepl("MALAT1", rownames(seu.ft)), ]
seu.ft <- seu.ft[!grepl("^MT-", rownames(seu.ft)), ]

# like in the tutorial I'm following MALAT1 is the top most expressed gene.  The top genes are a lot of MT and Ribosomal genes

seu.ft[["percent.rb"]] <- PercentageFeatureSet(seu.ft, pattern = "^RP")

seu.d = NormalizeData(seu.ft)
seu.d = FindVariableFeatures(seu.d, verbose = F)
seu.d = ScaleData(seu.d, vars.to.regress = c("nFeature_RNA", "percent.mt"),
    verbose = F)
seu.d = RunPCA(seu.d, verbose = F, npcs = 15)
seu.d = RunUMAP(seu.d, dims = 1:10, verbose = F)

nExp <- round(ncol(seu.d) * 0.08)  # expect more doublets because there is a lot more cells
seu.d <- doubletFinder_v3(seu.d, pN = 0.25, pK = 0.09, nExp = nExp, PCs = 1:10)
# the memory limit is reached here - I could run on compute canada
# For now I'll downsample
# this works

# name of the DF prediction can change, so extract the correct column name.
DF.name = colnames(seu.d@meta.data)[grepl("DF.classification", colnames(seu.d@meta.data))]


cowplot::plot_grid(ncol = 2, DimPlot(seu.d, group.by = "orig.ident") + NoAxes(),
    DimPlot(seu.d, group.by = DF.name) + NoAxes())

VlnPlot(seu.d, features = "nFeature_RNA", group.by = DF.name, pt.size = 0.1)

seu.d <- seu.d[, seu.d@meta.data[, DF.name]== "Singlet"]
dim(seu.d)
dim(seu.ft)

Cluster

seu <- NormalizeData(seu.d, normalization.method = "LogNormalize", scale.factor = 10000)
seu <- FindVariableFeatures(seu, selection.method = "vst", nfeatures = 2000)
seu <- ScaleData(seu)
seu <- RunPCA(seu)
seu <- RunUMAP(seu, reduction = "pca", n.neighbors = 25, dims = 1:30)
DimPlot(seu, reduction = "umap")

seu.q <- FindNeighbors(seu, dims = 1:25, k.param = 25)
seu.q <- FindClusters(seu.q, resolution = c(0,0.05,0.2,0.4,0.5,0.6,0.8))
library(clustree)

DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.05')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.1')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.2')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.4')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.6')
DimPlot(seu.q, reduction = "umap", group.by = 'RNA_snn_res.0.8')
clustree(seu.q)
# 0.4 is likely the best annotate subgroups

Predict cell types


# SNCA and control midbrain organoids 165 days in culture
MBO <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/AST23_BrainComm/MBOclusters_names29072021.rds")

# Midbrain  AIW002 120 days in culture
AIWMBO <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/AIWtrio120days/MOintegratedClusterK123res0.8.names_nov16_2021")

# Midbrain AIW002 60 days in culture

AIW60 <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/AIWtrio60days/AWI002ParkinKOPinkKO60days_labels_14052022.rds")


#first predict with the MBO data
Idents(MBO) <- "cluster_labels"
DefaultAssay(MBO) <- "RNA"

# find the reference anchors
print("finding reference anchors")
anchors <- FindTransferAnchors(reference = MBO ,query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = MBO$cluster_labels)
seu.q <- AddMetaData(seu.q, metadata = predictions)

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$MBOAST23.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'MBOAST23.pred', label = TRUE)

# see how accurate the predictions are
seu.q$predicted.id <- ifelse(seu.q$prediction.score.max > 0.95, seu.q$predicted.id, "None")

Idents(seu.q) <- 'predicted.id'
seu.q$MBOAST23.thresh <- Idents(seu.q)
DimPlot(seu.q, group.by = 'predicted.id', label = TRUE)
table(seu.q$MBOAST23.pred)
table(seu.q$MBOAST23.thresh)


 
## check the proportion of cell types predicted in each cluster
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.4, seu.q$MBOAST23.pred))
t.lables$Freq <- as.double(t.lables$Freq)

# try bar chart
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity")

# clusters don't break up by the predicted cell types

############ another predictions now using the AIW organoids

Idents(AIWMBO) <- "res08names"
DefaultAssay(AIWMBO) <- "RNA"

anchors <- FindTransferAnchors(reference = AIWMBO ,query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = AIWMBO$res08names)
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$AIW120.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'AIW120.pred', label = TRUE)
 
## check the proportion of cell types predicted in each cluster
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.4, seu.q$MBOAIW.pred))
t.lables$Freq <- as.double(t.lables$Freq)
# try bar chart
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity")

# see how accurate the predictions are
seu.q$predicted.id <- ifelse(seu.q$prediction.score.max > 0.95, seu.q$predicted.id, "None")

Idents(seu.q) <- 'predicted.id'
seu.q$AIW120.thresh <- Idents(seu.q)
DimPlot(seu.q, group.by = 'AIW120.thresh', label = TRUE)
table(seu.q$AIW120.pred)
table(seu.q$AIW120.thresh)

# the predicted cell types make more sense from the AIW002 organoid
# now predict with the AIW002 60 days organoid

Idents(AIW60) <- "cluster.ids"
DefaultAssay(AIW60) <- "RNA"

anchors <- FindTransferAnchors(reference = AIW60, query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = AIW60$cluster.ids) 
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$AIW60.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'AIW60.pred', label = TRUE)
 
## check the proportion of cell types predicted in each cluster
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.4, seu.q$AIW60.pred))
t.lables$Freq <- as.double(t.lables$Freq)

# try bar chart
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity")

# see how accurate the predictions are
seu.q$predicted.id <- ifelse(seu.q$prediction.score.max > 0.95, seu.q$predicted.id, "None")

Idents(seu.q) <- 'predicted.id'
seu.q$AIW60.thresh <- Idents(seu.q)
DimPlot(seu.q, group.by = 'AIW60.thresh', label = TRUE)
table(seu.q$AIW60.pred)
table(seu.q$AIW60.thresh)



# most of the cells are predicted as NPCs in many populations
# save with predictions so far
#saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia2LabledSeu03102022.RDS")

seu.q <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia2LabledSeu03102022.RDS")

See how many cells are predicted as astrocytes with the threshold


DAsubtypes <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/Macosko_Data/DAsubgroups_processed.Rds")

Idents(astro.ref) <- "Cell_Subtype"
DefaultAssay(astro.ref) <- "RNA"

# find the reference anchors
print("finding reference anchors")
anchors <- FindTransferAnchors(reference = DAsubtypes ,query = seu.q, dims = 1:20)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = astro.ref$Cell_Subtype, k.weight = 10)
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$astro.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'astro.pred', label = TRUE)
table(seu.q$astro.pred)

seu.q$predicted.id <- ifelse(seu.q$prediction.score.max > 0.95, seu.q$predicted.id, "none")
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
seu.q$astro.pred.thresh <- Idents(seu.q)
DimPlot(seu.q, group.by = 'astro.pred.thresh', label = TRUE)
table(seu.q$astro.pred.thresh)


t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$astro.pred.thresh))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 
top.pred.astro <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.astro <- top.pred.astro[order(top.pred.astro$Var1,-top.pred.astro$Freq),]
row.names(df.top.astro) <- NULL


t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$astro.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 
top.pred.astro <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.astro <- top.pred.astro[order(top.pred.astro$Var1,-top.pred.astro$Freq),]
row.names(df.top.astro) <- NULL

# a lot of these cells are also getting labelled as astrocytes

Do these get labelled as DA neurons too???

seu.q <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia2LabledSeu03102022.RDS")

DAsubtypes <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/Macosko_Data/DAsubgroups_processed.Rds")
Idents(DAsubtypes) <- "Cell_Subtype"
da.ref <- subset(DAsubtypes, downsample = 500)

# find the reference anchors
print("finding reference anchors")
anchors <- FindTransferAnchors(reference = da.ref, query = seu.q, dims = 1:20)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = da.ref$Cell_Subtype, k.weight = 10)
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
# add new dataslot for MBO predicted ID to make the next prediction
seu.q$da.pred <- Idents(seu.q)
DimPlot(seu.q, group.by = 'da.pred', label = TRUE)
table(seu.q$da.pred)

seu.q$predicted.id <- ifelse(seu.q$prediction.score.max > 0.95, seu.q$predicted.id, "none")

Idents(seu.q) <- 'predicted.id'
seu.q$da.pred.thresh <- Idents(seu.q)
DimPlot(seu.q, group.by = 'da.pred.thresh', label = TRUE)
table(seu.q$da.pred.thresh)


t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$da.pred.thresh))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 
top.pred.astro <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.astro <- top.pred.astro[order(top.pred.astro$Var1,-top.pred.da$Freq),]
row.names(df.top.astro) <- NULL


t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$astro.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 
top.pred.astro <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.astro <- top.pred.astro[order(top.pred.astro$Var1,-top.pred.astro$Freq),]
row.names(df.top.astro) <- NULL


# after thresholding very few cells are predicted as neurons

{redicte with the brain scRNAseq


pathway <- "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/"
seu.q <- readRDS(paste(pathway,"Glia2LabledSeu03102022.RDS",sep = ""))

# midbrain and striatum

seu.r <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PublicData/Bhaduri_wholeBrain/Bhaduri_midbrain_striatum.RDS")

Idents(seu.r) <- "cell_cluster"

# find the reference anchors
anchors <- FindTransferAnchors(reference = seu.r, query = seu.q, dims = 1:25)
Performing PCA on the provided reference using 1841 features as input.
Projecting cell embeddings
Finding neighborhoods
Finding anchors
    Found 881 anchors
Filtering anchors
    Retained 303 anchors
print("getting predictions")
[1] "getting predictions"
predictions <- TransferData(anchorset = anchors, refdata = seu.r$cell_cluster)
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Predicting cell labels
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Astrocyte_4     Endo_11      Endo_4      Endo_7    Neuron_2   Neuron_37   Neuron_98 
       5810           4         506         186          41           6         396 
Idents(seu.q) <- 'predicted.id'
seu.q$Bha.mid.stri.pred <- Idents(seu.q)
print(table(seu.q$Bha.mid.stri.pred))

Astrocyte_4    Neuron_2   Neuron_98      Endo_4      Endo_7     Endo_11   Neuron_37 
       5810          41         396         506         186           4           6 
seu.q$predicted.id <- ifelse(seu.q$prediction.score.max > 0.95, seu.q$predicted.id, "none")
Idents(seu.q) <- 'predicted.id'
seu.q$Bha.mid.pred.thresh <- Idents(seu.q)
DimPlot(seu.q, group.by = 'Bha.mid.pred.thresh', label = TRUE)

table(seu.q$Bha.mid.pred.thresh)

       none Astrocyte_4 
       6942           7 
DimPlot(seu.q, group.by = 'Bha.mid.pred.thresh')



# read in the reference dataset
# whole brain Bhaduri down sampled
seu.r <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PublicData/Bhaduri_wholeBrain/Bhaduri_downsample.RDS")

Idents(seu.r) <- "cell_cluster"

# find the reference anchors
anchors <- FindTransferAnchors(reference = seu.r, query = seu.q, dims = 1:25)
Performing PCA on the provided reference using 1844 features as input.
Projecting cell embeddings
Finding neighborhoods
Finding anchors
    Found 1726 anchors
Filtering anchors
    Retained 509 anchors
print("getting predictions")
[1] "getting predictions"
predictions <- TransferData(anchorset = anchors, refdata = seu.r$cell_cluster)
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Predicting cell labels
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

      Astrocyte_1       Astrocyte_2       Astrocyte_4       Astrocyte_6       Dividing_21 
              480               203              1310                 2               136 
       Dividing_3            Endo_1           Endo_11            Endo_2            Endo_3 
                7                85                19               522                 1 
           Endo_4            Endo_7            Endo_8  GW19_2_45Outlier GW19_Astrocyte_35 
                2                 3               125              1604                 1 
GW20_Astrocyte_39    GW22both_RG_23     Interneuron_7            IPC_29            IPC_34 
              138               252               192               747               350 
      Microglia_6          Neuron_5         Neuron_93          Oligo_12           Oligo_9 
                5                 6               253                11                 1 
             RG_1             RG_11              RG_6 
              492                 1                 1 
Idents(seu.q) <- 'predicted.id'
seu.q$Bha.pred <- Idents(seu.q)
print(table(seu.q$Bha.pred))

      Astrocyte_2  GW19_2_45Outlier            Endo_8            IPC_29            IPC_34 
              203              1604               125               747               350 
    Interneuron_7       Dividing_21       Astrocyte_4 GW20_Astrocyte_39       Astrocyte_1 
              192               136              1310               138               480 
        Neuron_93    GW22both_RG_23            Endo_2           Endo_11            Endo_1 
              253               252               522                19                85 
             RG_1          Neuron_5            Endo_3       Microglia_6        Dividing_3 
              492                 6                 1                 5                 7 
         Oligo_12              RG_6            Endo_7            Endo_4       Astrocyte_6 
               11                 1                 3                 2                 2 
GW19_Astrocyte_35           Oligo_9             RG_11 
                1                 1                 1 
DimPlot(seu.q, group.by = 'Bha.pred')
DimPlot(seu.q, group.by = 'subgroups')

Compare predictions - make a predictions table


# AIW002 120 days predictions - take the thresholded options
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$AIW120.thresh))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.AIW120 <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.aiw120 <- top.pred.celltype.AIW120[order(top.pred.celltype.AIW120$Var1,-top.pred.celltype.AIW120$Freq),]
row.names(df.top.aiw120) <- NULL
df.top.aiw120$I <- row.names(df.top.aiw120)

# AIW002 60 days predictions
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$AIW60.thresh))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.AIW60 <-as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.aiw60 <- top.pred.celltype.AIW60[order(top.pred.celltype.AIW60$Var1,-top.pred.celltype.AIW60$Freq),]
row.names(df.top.aiw60) <- NULL
df.top.aiw60$I <- row.names(df.top.aiw60)


# AST23 165 days predictions
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$MBOAST23.thresh))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.AST23 <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.AST23 <- top.pred.celltype.AST23[order(top.pred.celltype.AST23$Var1,-top.pred.celltype.AST23$Freq),]
row.names(df.top.AST23) <- NULL
df.top.AST23$I <- row.names(df.top.AST23)

# add the threshold Astro predictions 
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$astro.pred.thresh))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.astro <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.astro <- top.pred.celltype.astro[order(top.pred.celltype.astro$Var1,-top.pred.celltype.astro$Freq),]
row.names(df.top.astro) <- NULL
df.top.astro$I <- row.names(df.top.astro)

# add the neurons predictions 
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$da.pred.thresh))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.da <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.da <- top.pred.celltype.da[order(top.pred.celltype.da$Var1,-top.pred.celltype.da$Freq),]
row.names(df.top.da) <- NULL
df.top.da$I <- row.names(df.top.da)




### add in the prediction from brain data Bhaduri midbrain and striatum
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$Bha.mid.stri.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.Bha <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.Bha <- top.pred.celltype.Bha[order(top.pred.celltype.Bha$Var1,-top.pred.celltype.Bha$Freq),]
row.names(df.top.Bha) <- NULL
df.top.Bha$I <- row.names(df.top.Bha)

## these are calculated below
### add in the prediction from brain whole brain data Bhaduri midbrain down sampled
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$Bha.pred))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype.Bha1 <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top.Bha1 <- top.pred.celltype.Bha1[order(top.pred.celltype.Bha$Var1,-top.pred.celltype.Bha$Freq),]
row.names(df.top.Bha1) <- NULL
df.top.Bha1$I <- row.names(df.top.Bha1)

pred.table <- merge(df.top.AST23, df.top.aiw60, by = 'I', all = TRUE)
pred.table <- merge(pred.table, df.top.aiw120, by = 'I')
pred.table <- merge(pred.table, df.top.Bha, by = 'I')
Warning in merge.data.frame(pred.table, df.top.Bha, by = "I") :
  column names ‘Var1.x’, ‘Var2.x’, ‘Freq.x’, ‘Var1.y’, ‘Var2.y’, ‘Freq.y’ are duplicated in the result
pred.table <- merge(pred.table, df.top.Bha1, by = 'I')
Warning in merge.data.frame(pred.table, df.top.Bha1, by = "I") :
  column names ‘Var1.x’, ‘Var2.x’, ‘Freq.x’, ‘Var1.y’, ‘Var2.y’, ‘Freq.y’ are duplicated in the result
pred.table
NA
NA
NA

Predicted cluster annotations 0 Unknown/ NPC 1 RG 2 astro 3 RG 4 neurons 5 RG

Predict from developing cortex

anchors <- FindTransferAnchors(reference = seu.r, query = seu.q, dims = 1:25)
Performing PCA on the provided reference using 1389 features as input.
Projecting cell embeddings
Finding neighborhoods
Error in base::options(...future.oldOptions) : invalid argument

The dev cortex doesn’t predict Glia 2 well Try the developing forebrain

DefaultAssay(seu.r) <- 'RNA'

# clusters has subgroups
# levels are main cell groups 
Idents(seu.r) <- "Level1"


# find the reference anchors
anchors <- FindTransferAnchors(reference = seu.r, query = seu.q, dims = 1:25)
Performing PCA on the provided reference using 1851 features as input.
Projecting cell embeddings
Finding neighborhoods
Finding anchors
    Found 585 anchors
Filtering anchors
    Retained 250 anchors
print("getting predictions")
[1] "getting predictions"
predictions <- TransferData(anchorset = anchors, refdata = seu.r$Level1)
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Predicting cell labels
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

 EarlyInhibitory        Glioblast NeuralProgenitor       RadialGlia             VLMC 
               7             2893             1299             2630              120 
Idents(seu.q) <- 'predicted.id'
seu.q$fb.pred <- Idents(seu.q)
print(table(seu.q$fb.pred))

      RadialGlia        Glioblast NeuralProgenitor  EarlyInhibitory             VLMC 
            2630             2893             1299                7              120 
DimPlot(seu.q, group.by = 'fb.pred')



# add the threshold 
seu.q$predicted.id <- ifelse(seu.q$prediction.score.max > 0.80, seu.q$predicted.id, "none")
Idents(seu.q) <- 'predicted.id'
seu.q$fb.thresh <- Idents(seu.q)
DimPlot(seu.q, group.by = 'fb.thresh', label = TRUE)

table(seu.q$fb.thresh)

      RadialGlia             none             VLMC NeuralProgenitor 
            1028             5659              113              149 
# make the tables 
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$fb.thresh))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(2, Freq))
df.top <- top.pred.celltype[order(top.pred.celltype$Var1,-top.pred.celltype$Freq),]
row.names(df.top) <- NULL
df.top$I <- row.names(df.top)

#VLMC is vascular and leptomeninges

# almost everything is predicted as 'none' when theshold is .95 
# run again with lower threshold 0.8 and many are predicted as RG

# try predicting with the cluster labels 
# later I can subset cell types for the reference data

Idents(seu.r) <- "Clusters"

anchors <- FindTransferAnchors(reference = seu.r, query = seu.q, dims = 1:25)
Performing PCA on the provided reference using 1851 features as input.
Projecting cell embeddings
Finding neighborhoods
Finding anchors
    Found 585 anchors
Filtering anchors
    Retained 250 anchors
print("getting predictions")
[1] "getting predictions"
predictions <- TransferData(anchorset = anchors, refdata = seu.r$Clusters)
Finding integration vectors
Finding integration vector weights
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
Predicting cell labels
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

           Excitatory neurons possibly midbrain                               Glioblast/Pre-OPC 
                                           1947                                               4 
                                           OPCs                        Radial Glia VLMC primed? 
                                              1                                            2931 
Radial glia/Glioblast/Forebrain progenitor EMX1                       Striatum/Cortical neurons 
                                             75                                            1871 
                                          VLMCs 
                                            120 
Idents(seu.q) <- 'predicted.id'
seu.q$fb.sub.pred <- Idents(seu.q)
print(table(seu.q$fb.sub.pred))

                       Radial Glia VLMC primed?            Excitatory neurons possibly midbrain 
                                           2931                                            1947 
                      Striatum/Cortical neurons Radial glia/Glioblast/Forebrain progenitor EMX1 
                                           1871                                              75 
                                          VLMCs                                            OPCs 
                                            120                                               1 
                              Glioblast/Pre-OPC 
                                              4 
DimPlot(seu.q, group.by = 'fb.sub.pred')



# add the threshold 
seu.q$predicted.id <- ifelse(seu.q$prediction.score.max > 0.80, seu.q$predicted.id, "none")
Idents(seu.q) <- 'predicted.id'
seu.q$fb.sub.thresh <- Idents(seu.q)
DimPlot(seu.q, group.by = 'fb.sub.thresh', label = TRUE)

table(seu.q$fb.sub.thresh)

            Radial Glia VLMC primed?                                 none 
                                1015                                 5727 
                               VLMCs Excitatory neurons possibly midbrain 
                                 113                                   94 
t.lables <- as.data.frame(table(seu.q$RNA_snn_res.0.2, seu.q$fb.sub.thresh))
t.lables$Freq <- as.double(t.lables$Freq)
ggplot(t.lables, aes(y = Freq, x = Var1, fill = Var2)) + geom_bar(position = "stack", stat= "identity") + RotatedAxis() 

top.pred.celltype <- as.data.frame(t.lables  %>% group_by(Var1)  %>% top_n(4, Freq))
df.top <- top.pred.celltype[order(top.pred.celltype$Var1,-top.pred.celltype$Freq),]
row.names(df.top) <- NULL
df.top$I <- row.names(df.top)

df.top.ft <- df.top %>% filter(Freq > 0)

Predictions with thresholds:

0 - RG 1 - RG 2 - none 3 - RG 4 - Neural precursor 5 - VLMC (vascular and leptomeninges)

Look at gene lists with known markers


Idents(seu.q) <- 'RNA_snn_res.0.2'

# many cell types list
feature_list = c("MKI67","SOX2","POU5F1","DLX2","PAX6","SOX9","HES1","NES","RBFOX3","MAP2","NCAM1","CD24","GRIA2","GRIN2B","GABBR1","GAD1","GAD2","GABRA1","GABRB2","TH","ALDH1A1","LMX1B","NR4A2","CORIN","CALB1","KCNJ6","CXCR4","ITGA6","SLC1A3","CD44","AQP4","S100B", "PDGFRA","OLIG2","MBP","CLDN11","VIM","VCAM1")

DoHeatmap(seu.q, features = feature_list, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = feature_list) +RotatedAxis()

# Dopaminergic markers
PD_poulin = c("TH","SLC6A3","SLC18A2","SOX6","NDNF","SNCG","ALDH1A1","CALB1","TACR2","SLC17A6","SLC32A1","OTX2","GRP","LPL","CCK","VIP")

DoHeatmap(seu.q, features = PD_poulin, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = PD_poulin)+RotatedAxis()

ealryNeur = c("DCX","NEUROD1","TBR1")
proliferation = c("PCNA","MKI67")
neuralstem = c("SOX2","NES","PAX6","MASH1")

feature_list <- c("DCX","NEUROD1","TBR1","PCNA","MKI67","SOX2","NES","PAX6","MASH1")
DoHeatmap(seu.q, features = feature_list, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = feature_list)+RotatedAxis()


mat_neuron = c("RBFOX3","SYP","DLG45","VAMP1","VAMP2","TUBB3","SYT1","BSN","HOMER1","SLC17A6") 
# NeuN is FOX3 - RBFOX3
# PSD95 also SP-90 or DLG4
# VGLUT2 is SLC17A6
DoHeatmap(seu.q, features = mat_neuron, size=3, angle =90, group.bar.height = 0.02)
# cluster 4 also show mature neuron markers
DotPlot(seu.q, features = mat_neuron)+RotatedAxis()
# excitatory neuron markers
ex = c("GRIA2","GRIA1","GRIA4","GRIN1","GRIN2B","GRIN2A","GRIN3A","GRIN3","GRIP1","CAMK2A")
DoHeatmap(seu.q, features = ex, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = ex)+RotatedAxis()
# inhibitory neuron markers
inh = c("GAD1","GAD2", "GAT1","PVALB","GABR2","GABR1","GBRR1","GABRB2","GABRB1","GABRB3","GABRA6","GABRA1","GABRA4","TRAK2")
DoHeatmap(seu.q, features = inh, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = inh)+RotatedAxis()
# cluster 4 is more excitatory than inhbitory but neither marker set has much expression 

### glia markers
microglia = c("PTPRC","AIF1","ADGRE1")  # ADGRE1 is a microglia marker F4/80, CD45 is PTPRC, gene name IBA1 is AIF1
astolgNPCpromicro = c("GFAP","S100B","SLC1A2","MBP","SOX10","SPP1","DCX","NEUROD1","TBR1","PCNA","MKI67","PTPRC","AIF1","ADGRE1")
# note GLT1 is EAAT2 which is SLC1A2 glutatmate transporter
# epithelial
epi = c("HES1","HES5","SOX2","SOX10","NES","CDH1","NOTCH1") # e-cadherin is CDH1

DoHeatmap(seu.q, features = astolgNPCpromicro, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = astolgNPCpromicro)+RotatedAxis()
# cluster 4 is more excitatory than inhbitory but neither marker set has much expression 
DoHeatmap(seu.q, features = epi, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = epi)+RotatedAxis()

# also add Radial glia marker overlap with Glia and Neurons

features <- c("PTPRC","AIF1","ADGRE1", "VIM", "TNC","PTPRZ1","FAM107A","HOPX","LIFR",
              "ITGB5","IL6ST")
DoHeatmap(seu.q, features = features, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = features)+RotatedAxis()

# radial glia markers
rg <- c("VIM","NES","PAX6","HES1","EAAT1","NCAD1","SOX2","FABP7")
DoHeatmap(seu.q, features = rg, size=3, angle =90, group.bar.height = 0.02)
DotPlot(seu.q, features = rg)+RotatedAxis()

# NPC and radial glia are very similar

Marker expression predictions Cluster 0 - unknown Cluster 1 - RG Cluster 2 - unknown Cluster 3 - RG cluster 4 - immature neurons Cluster 5 - RG, opc

Check the levels of RNA in each cluster

VlnPlot(seu.q, features = "nFeature_RNA")

Cluster 0 and 2 have fewer sequences than other groups and thus no markers Possibly remove these is they don’t come up with some markers

Find cluster markers

Idents(seu.q) <- 'RNA_snn_res.0.2'
ClusterMarkers <- FindAllMarkers(seu.q, only.pos = TRUE)

top5 <- ClusterMarkers %>% group_by(cluster) %>% top_n(n=5, wt = avg_log2FC)
DoHeatmap(seu.q, features = top5$gene, size=3, angle =90, group.bar.height = 0.02)

#write.csv(ClusterMarkers,"/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/Glia2RGClusterMarkers_new.csv")

Idents(seu.q) <- 'RNA_snn_res.0.1'
ClusterMarkers <- FindAllMarkers(seu.q, only.pos = TRUE)

top5 <- ClusterMarkers %>% group_by(cluster) %>% top_n(n=5, wt = avg_log2FC)
DoHeatmap(seu.q, features = top5$gene, size=3, angle =90, group.bar.height = 0.02)

Markers of 2 are matching with 5 possibly merge these together Cluster 0 markers don’t look up regulated but the list is long

Look at the libraries

library(enrichR)

setEnrichrSite("Enrichr") # Human genes
# list of all the databases

# libaries with cell types

db <- c('Descartes_Cell_Types_and_Tissue_2021',
        'CellMarker_Augmented_2021','Azimuth_Cell_Types_2021')

# enrichr(genes, databases = NULL)

#I'll run the clusters one at a time

N1.c0 <- ClusterMarkers %>% filter(cluster == 0 & avg_log2FC > 0)
genes <- N1.c0$gene

N1.c0.Er <- enrichr(genes, databases = db)
plotEnrich(N1.c0.Er[[1]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c0.Er[[2]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")
plotEnrich(N1.c0.Er[[3]], showTerms = 20, numChar = 40, y = "Count", orderBy = "P.value")


N1.Er.genes.1 <- N1.c0.Er[[1]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.1

N1.Er.genes.2 <- N1.c0.Er[[2]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.2

N1.Er.genes.3 <- N1.c0.Er[[3]] %>% select(Term, Genes, Combined.Score)
N1.Er.genes.3

The adult brain doesn’t predict radial glia - there are radial glia but I believe these are different from the ‘neuroblast’ type radial glia

I will use a developing brain reference

DimPlot(seu.q)

seu.q <- readRDS(paste(pathway,"Glia2LabledSeu03102022.RDS",sep = ""))

# midbrain and striatum

seu.r <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PublicData/Bhaduri_wholeBrain/Bhaduri_midbrain_striatum.RDS")

Idents(seu.r) <- "cell_cluster"

# find the reference anchors
anchors <- FindTransferAnchors(reference = seu.r, query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = seu.r$cell_cluster)
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
seu.q$Bha.mid.stri.pred <- Idents(seu.q)
print(table(seu.q$Bha.mid.stri.pred))


seu.q$predicted.id <- ifelse(seu.q$prediction.score.max > 0.95, seu.q$predicted.id, "none")
Idents(seu.q) <- 'predicted.id'
seu.q$Bha.mid.pred.thresh <- Idents(seu.q)
DimPlot(seu.q, group.by = 'Bha.mid.pred.thresh', label = TRUE)
table(seu.q$Bha.mid.pred.thresh)
DimPlot(seu.q, group.by = 'Bha.mid.pred.thresh')


# read in the reference dataset
# whole brain Bhaduri down sampled
seu.r <- readRDS("/Users/rhalenathomas/Documents/Data/scRNAseq/PublicData/Bhaduri_wholeBrain/Bhaduri_downsample.RDS")

Idents(seu.r) <- "cell_cluster"

# find the reference anchors
anchors <- FindTransferAnchors(reference = seu.r, query = seu.q, dims = 1:25)
print("getting predictions")
predictions <- TransferData(anchorset = anchors, refdata = seu.r$cell_cluster)
seu.q <- AddMetaData(seu.q, metadata = predictions)
print(table(seu.q$predicted.id))

Idents(seu.q) <- 'predicted.id'
seu.q$Bha.pred <- Idents(seu.q)
print(table(seu.q$Bha.pred))
DimPlot(seu.q, group.by = 'Bha.pred')
DimPlot(seu.q, group.by = 'subgroups')

seu.q$predicted.id <- ifelse(seu.q$prediction.score.max > 0.95, seu.q$predicted.id, "none")
Idents(seu.q) <- 'predicted.id'
seu.q$Bha.mid.pred.thresh <- Idents(seu.q)
DimPlot(seu.q, group.by = 'Bha.pred.thresh', label = TRUE)
table(seu.q$Bha.mid.pred.thresh)
DimPlot(seu.q, group.by = 'Bha.pred.thresh')

Add some cell type annotations


Idents(seu.q) <- 'RNA_snn_res.0.2'

cluster.ids <- c("Glia1","RG1","Glia2","RG2","NeuronsImmature","RG3")

names(cluster.ids) <- levels(seu.q)
seu.q <- RenameIdents(seu.q, cluster.ids)
seu.q$subgroups <- Idents(seu.q)

#DimPlot(seu.q, group.by = 'RNA_snn_res.0.2', label = TRUE)
DimPlot(seu.q, reduction = "umap", label = TRUE, group.by = 'subgroups', repel = TRUE)
# save file
saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia2LabledSeu03102022.RDS")

Main cell groups


Idents(seu.q) <- 'RNA_snn_res.0.2'

cluster.ids <- c("Radial Glia","Radial Glia","Radial Glia","Radial Glia","NPC","Other")

names(cluster.ids) <- levels(seu.q)
seu.q <- RenameIdents(seu.q, cluster.ids)
seu.q$Cell_Types <- Idents(seu.q)

#DimPlot(seu.q, group.by = 'RNA_snn_res.0.2', label = TRUE)
DimPlot(seu.q, reduction = "umap", label = TRUE, group.by = 'Cell_Types', repel = TRUE)


saveRDS(seu.q, "/Users/rhalenathomas/Documents/Data/scRNAseq/PhenoID/scRNAseqSorted/objs/Glia2LabledSeu03102022.RDS")

Proportions of cell types


table(seu.q$Cell_Types)
dim(seu.q)

prp <- as.data.frame(table(seu.q$Cell_Types))
prp

prp$prop <- prp$Freq/sum(prp$Freq)*100
prp$Sample <- 'RadialGlia'
prp

I’ll calculate the proportions for each cell type and make a table or plot in the comparison workbook.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpTaW5nbGUgY2VsbCBzZXEgYWZ0ZXIgc29ydGluZyBmb3IgUGhlbm9JRAoKc2FtcGxlMSA9IE5ldXJvbnMxCnNhbXBsZTIgPSBOZXVyb25zMgpzYW1wbGUzID0gR2xpYTEgLSBBc3Ryb2N5dGVzIChDRDQ0KykKc2FtcGxlNCA9IEdsaWEyIC0gUmFkaWFsIEdsaWEgKENENDQtKQoKSW4gSFBDIEkgaGF2ZSBydW4gc3RlcHMgb2Ygc2NybmFib3ggKGN1c3RvbSBwaXBlbGluZSBpbiBwcm9ncmVzcykKMS4gQ2VsbCBSYW5nZXIgZm9yIGZlYXR1cmUgc2VxCjIuIENyZWF0ZSBTZXVyYXQgT2JqZWN0cyAKMy4gQXBwbHkgbWluaW11bSBmaWx0ZXJpbmcgYW5kIGNhbGN1bGF0ZSBwZXJjZW50IG1pdG9jaG9uZHJpYS4KCkkgaGF2ZSB0ZWNobmljYWwgMyByZXBsaWNhdGVzIHdpdGggaGFzaHRhZyBsYWJlbHMgYXQgdGhpcyBwb2ludCBJIGhhdmVuJ3QgeWV0IGRlbXVsdGlwbGV4IHRoZSBoYXNodGFncy4gVGhlIGRhdGEgaGVyZSB3aWxsIGJlIHRyZWF0ZWQgYXMgb25lIHNhbXBsZS4gIEkgc29ydGVkIHRocmVlIHNlcGFyYXRlIHNhbXBsZXMgYW5kIHBvb2xlZCB0aGVtIHRvZ2V0aGVyLiAKCgpgYGB7cn0KIyBzZXQgdXAgdGhlIGVudmlyb25tZW50CgpsaWJyYXJ5KFNldXJhdCkKbGlicmFyeShkcGx5cikKbGlicmFyeShNYXRyaXgpCmxpYnJhcnkoZ2dwbG90MikKCiNybShsaXN0ID0gbHMoKSkKCgpgYGAKCgpSZWFkIGluIHRoZSBzZXVyYXQgb2JqZWN0cyBtYWRlIGluIGNvbXB1dGUgY2FuYWRhCgpgYGB7cn0KCiMgdGhpcyBzZWVtcyB0byBuZXZlciBsb2FkIEknbGwgdXNlIHN0ZXAgMyBvdXRwdXQgdGhhdCBoYXMgc29tZSBmaWx0ZXJpbmcgCiMgbkZlYXR1cmVfUk5BID4gMTgwIGFuZCBwZXJjZW50Lm10IDwgMjUKCnBhdGh3YXkgPC0gIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BoZW5vSUQvc2NSTkFzZXFTb3J0ZWQvb2Jqcy8iCgpOZXVyb25zMSA8LSByZWFkUkRTKHBhc3RlKHBhdGh3YXksInNldTEucmRzIixzZXAgPSAiIikpCk5ldXJvbnMyIDwtIHJlYWRSRFMocGFzdGUocGF0aHdheSwic2V1Mi5yZHMiLHNlcCA9ICIiKSkKR2xpYTEgPC0gcmVhZFJEUyhwYXN0ZShwYXRod2F5LCJzZXUzLnJkcyIsc2VwID0gIiIpKQpHbGlhMiA8LSByZWFkUkRTKHBhc3RlKHBhdGh3YXksInNldTQucmRzIixzZXAgPSAiIikpCgpOZXVyb25zMQpOZXVyb25zMgpHbGlhMQpHbGlhMgoKCmBgYAoKCkhhdmUgYSBsb29rIGF0IHRoZSBvYmplY3RzIHRoYXQgYWxyZWFkeSBoYXZlIHNvbWUgZmlsdGVyaW5nCgoKU2VlIHRoZSB2aW9saW4gcGxvdHMgCgpgYGB7cn0KClZsblBsb3QoTmV1cm9uczEsIHB0LnNpemUgPSAwLjEwLCBmZWF0dXJlcyA9IGMoIm5GZWF0dXJlX1JOQSIsICJuQ291bnRfUk5BIiwgInBlcmNlbnQubXQiKSwgbmNvbCA9IDMpCgpWbG5QbG90KE5ldXJvbnMxLCBwdC5zaXplID0gMC4xMCwgZmVhdHVyZXMgPSBjKCJuRmVhdHVyZV9STkEiKSwgeS5tYXggPSA1MDApClZsblBsb3QoTmV1cm9uczEsIHB0LnNpemUgPSAwLjEwLCBmZWF0dXJlcyA9IGMoIm5Db3VudF9STkEiKSwgeS5tYXggPSAyMDAwKQoKCiMgZmlsdGVyIG1vcmUgY2VsbHMKCk5ldXJvbjEuZnQgPC0gc3Vic2V0KE5ldXJvbnMxLCBzdWJzZXQgPSBuRmVhdHVyZV9STkEgPiAyNTAgJiBuQ291bnRfUk5BID4gMjUwICYgbkNvdW50X1JOQSA8IDEwMDAwKSAKTmV1cm9uMS5mdAoKIyAzMzU0MSBmZWF0dXJlcyBhY3Jvc3MgMTgzMyBzYW1wbGVzCgoKYGBgCgoKRmlsdGVycyBvdXQgc3BlY2lmaWMgZ2VuZXMKCmBgYHtyfQoKIyBmaWx0ZXIgb3V0IE1BTEFUMSBzdXBlciBoaWdoIGV4cHJlc3Npb24KCnNldS5mdCA8LSBzZXVbIWdyZXBsKCJNQUxBVDEiLCByb3duYW1lcyhzZXUpKSwgXQpzZXUuZnQgPC0gc2V1LmZ0WyFncmVwbCgiXk1ULSIsIHJvd25hbWVzKHNldS5mdCkpLCBdCgojIHRoaXMgZmlsdGVyZWQgb2JqZWN0IG1pZ2h0IGNsdXN0ZXIgZGlmZmVyZW50bHkKCgpgYGAKClBDQSBhbmQgVU1BUAoKYGBge3J9CgpzZXUucSA8LSBOb3JtYWxpemVEYXRhKHNldS5mdCwgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiTG9nTm9ybWFsaXplIiwgc2NhbGUuZmFjdG9yID0gMTAwMDApCnNldS5xIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKHNldS5xLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCnNldS5xIDwtIFNjYWxlRGF0YShzZXUucSkKc2V1LnEgPC0gUnVuUENBKHNldS5xKQpzZXUucSA8LSBSdW5VTUFQKHNldS5xLCByZWR1Y3Rpb24gPSAicGNhIiwgbi5uZWlnaGJvcnMgPSAyNSwgZGltcyA9IDE6MzAsIG1pbi5kaXN0ID0gMC4yNSwgc3ByZWFkID0gMikKCmBgYAoKClRyeSB0byBmaW5kIGRvdWJsZXRzIHdpdGggZG91YmxldCBmaW5kZXIKCmBgYHtyfQpyZW1vdGVzOjppbnN0YWxsX2dpdGh1YignY2hyaXMtbWNnaW5uaXMtdWNzZi9Eb3VibGV0RmluZGVyJykKc3VwcHJlc3NNZXNzYWdlcyhyZXF1aXJlKERvdWJsZXRGaW5kZXIpKQoKCmBgYAoKYGBge3J9CgpzZXUuZCA9IEZpbmRWYXJpYWJsZUZlYXR1cmVzKHNldS5xLCB2ZXJib3NlID0gRikKc2V1LmQgPSBTY2FsZURhdGEoc2V1LmQsIHZhcnMudG8ucmVncmVzcyA9IGMoIm5GZWF0dXJlX1JOQSIsICJwZXJjZW50Lm10IiksCiAgICB2ZXJib3NlID0gRikKc2V1LmQgPSBSdW5QQ0Eoc2V1LmQsIHZlcmJvc2UgPSBGLCBucGNzID0gMjApCnNldS5kID0gUnVuVU1BUChzZXUuZCwgZGltcyA9IDE6MTAsIHZlcmJvc2UgPSBGKQoKbkV4cCA8LSByb3VuZChuY29sKHNldS5kKSAqIDAuMDYpICAjIGV4cGVjdCA2JSBkb3VibGV0cwpzZXUuZCA8LSBkb3VibGV0RmluZGVyX3YzKHNldS5kLCBwTiA9IDAuMjUsIHBLID0gMC4wOSwgbkV4cCA9IG5FeHAsIFBDcyA9IDE6MTApCgoKIyBuYW1lIG9mIHRoZSBERiBwcmVkaWN0aW9uIGNhbiBjaGFuZ2UsIHNvIGV4dHJhY3QgdGhlIGNvcnJlY3QgY29sdW1uIG5hbWUuCkRGLm5hbWUgPSBjb2xuYW1lcyhzZXUuZEBtZXRhLmRhdGEpW2dyZXBsKCJERi5jbGFzc2lmaWNhdGlvbiIsIGNvbG5hbWVzKHNldS5kQG1ldGEuZGF0YSkpXQoKCgpjb3dwbG90OjpwbG90X2dyaWQobmNvbCA9IDIsIERpbVBsb3Qoc2V1LmQsIGdyb3VwLmJ5ID0gIm9yaWcuaWRlbnQiKSArIE5vQXhlcygpLAogICAgRGltUGxvdChzZXUuZCwgZ3JvdXAuYnkgPSBERi5uYW1lKSArIE5vQXhlcygpKQoKCmBgYAoKRG8gdGhlIGRvdWJsZSBjZWxscyBoYXZlIG1vcmUgZ2VuZXMgdGhhbiB0aGUgc2luZ2xldD8/CgpgYGB7cn0KClZsblBsb3Qoc2V1LmQsIGZlYXR1cmVzID0gIm5GZWF0dXJlX1JOQSIsIGdyb3VwLmJ5ID0gREYubmFtZSwgcHQuc2l6ZSA9IDAuMSkKIyB5ZXMgCgpgYGAKClJlbW92ZSB0aGUgZG91YmxldHMKCmBgYHtyfQoKc2V1LmQgPC0gc2V1LmRbLCBzZXUuZEBtZXRhLmRhdGFbLCBERi5uYW1lXT09ICJTaW5nbGV0Il0KZGltKHNldS5kKQpkaW0oc2V1KQoKIyByZW1vdmVkIGFib3V0IDEwMCBjZWxscwoKCmBgYAoKClJ1biBjbHVzdGVyaW5nCgpgYGB7cn0KCnNldS5xIDwtIEZpbmROZWlnaGJvcnMoc2V1LmQsIGRpbXMgPSAxOjI1LCBrLnBhcmFtID0gNDMpCnNldS5xIDwtIEZpbmRDbHVzdGVycyhzZXUucSwgcmVzb2x1dGlvbiA9IGMoMCwwLjIsMC40LDAuNikpCnNldS5xIDwtIEZpbmRDbHVzdGVycyhzZXUucSwgcmVzb2x1dGlvbiA9IGMoMS4yKSkKCmxpYnJhcnkoY2x1c3RyZWUpCmNsdXN0cmVlKHNldS5xLCBwcmVmaXggPSAiUk5BX3Nubl9yZXMuIikKRGltUGxvdChzZXUucSkKCmBgYAoKTG9vayBhdCB0aGUgcHJlZGljdGlvbnMgb2YgY2VsbCB0eXBlcyBpbiBzZXVyYXQgbGFiZWwgdHJhbnNmZXIKCjMgb3JnYW5vaWQgZGF0YXNldHMKCgpgYGB7cn0KCgojIFNOQ0EgYW5kIGNvbnRyb2wgbWlkYnJhaW4gb3JnYW5vaWRzIDE2NSBkYXlzIGluIGN1bHR1cmUKTUJPIDwtIHJlYWRSRFMoIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL0FTVDIzX0JyYWluQ29tbS9NQk9jbHVzdGVyc19uYW1lczI5MDcyMDIxLnJkcyIpCgojIE1pZGJyYWluICBBSVcwMDIgMTIwIGRheXMgaW4gY3VsdHVyZQpBSVdNQk8gPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvQUlXdHJpbzEyMGRheXMvTU9pbnRlZ3JhdGVkQ2x1c3RlcksxMjNyZXMwLjgubmFtZXNfbm92MTZfMjAyMSIpCgojIE1pZGJyYWluIEFJVzAwMiA2MCBkYXlzIGluIGN1bHR1cmUKCkFJVzYwIDwtIHJlYWRSRFMoIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL0FJV3RyaW82MGRheXMvQVdJMDAyUGFya2luS09QaW5rS082MGRheXNfbGFiZWxzXzE0MDUyMDIyLnJkcyIpCgoKIyBxdWVyeQojc2V1LnEgPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUGhlbm9JRC9zY1JOQXNlcVNvcnRlZC9vYmpzL05ldXJvbnNGaWx0ZXJlZFNldTI4MDkyMDIyLlJEUyIpCgoKI2ZpcnN0IHByZWRpY3Qgd2l0aCB0aGUgTUJPIGRhdGEKSWRlbnRzKE1CTykgPC0gImNsdXN0ZXJfbGFiZWxzIgpEZWZhdWx0QXNzYXkoTUJPKSA8LSAiUk5BIgoKIyBmaW5kIHRoZSByZWZlcmVuY2UgYW5jaG9ycwpwcmludCgiZmluZGluZyByZWZlcmVuY2UgYW5jaG9ycyIpCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBNQk8gLHF1ZXJ5ID0gc2V1LnEsIGRpbXMgPSAxOjI1KQpwcmludCgiZ2V0dGluZyBwcmVkaWN0aW9ucyIpCnByZWRpY3Rpb25zIDwtIFRyYW5zZmVyRGF0YShhbmNob3JzZXQgPSBhbmNob3JzLCByZWZkYXRhID0gTUJPJGNsdXN0ZXJfbGFiZWxzKQpzZXUucSA8LSBBZGRNZXRhRGF0YShzZXUucSwgbWV0YWRhdGEgPSBwcmVkaWN0aW9ucykKcHJpbnQodGFibGUoc2V1LnEkcHJlZGljdGVkLmlkKSkKCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKIyBhZGQgbmV3IGRhdGFzbG90IGZvciBNQk8gcHJlZGljdGVkIElEIHRvIG1ha2UgdGhlIG5leHQgcHJlZGljdGlvbgpzZXUucSRNQk9BU1QyMy5wcmVkIDwtIElkZW50cyhzZXUucSkKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnTUJPQVNUMjMucHJlZCcsIGxhYmVsID0gVFJVRSkKIAojIyBjaGVjayB0aGUgcHJvcG9ydGlvbiBvZiBjZWxsIHR5cGVzIHByZWRpY3RlZCBpbiBlYWNoIGNsdXN0ZXIKdC5sYWJsZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4wLjIsIHNldS5xJHByZWRpY3RlZC5pZCkpCnByLnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUocHJvcC50YWJsZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4wLjIsIHNldS5xJHByZWRpY3RlZC5pZCkpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQoKCiMgdHJ5IGJhciBjaGFydApnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpCgojIGNsdXN0ZXJzIGRvbid0IGJyZWFrIHVwIGJ5IHRoZSBwcmVkaWN0ZWQgY2VsbCB0eXBlcwoKIyMjIyMjIyMjIyMjIGFub3RoZXIgcHJlZGljdGlvbnMgbm93IHVzaW5nIHRoZSBBSVcgb3JnYW5vaWRzCgpJZGVudHMoQUlXTUJPKSA8LSAicmVzMDhuYW1lcyIKRGVmYXVsdEFzc2F5KEFJV01CTykgPC0gIlJOQSIKCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBBSVdNQk8gLHF1ZXJ5ID0gc2V1LnEsIGRpbXMgPSAxOjI1KQpwcmludCgiZ2V0dGluZyBwcmVkaWN0aW9ucyIpCnByZWRpY3Rpb25zIDwtIFRyYW5zZmVyRGF0YShhbmNob3JzZXQgPSBhbmNob3JzLCByZWZkYXRhID0gQUlXTUJPJHJlczA4bmFtZXMpCnNldS5xIDwtIEFkZE1ldGFEYXRhKHNldS5xLCBtZXRhZGF0YSA9IHByZWRpY3Rpb25zKQpwcmludCh0YWJsZShzZXUucSRwcmVkaWN0ZWQuaWQpKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwojIGFkZCBuZXcgZGF0YXNsb3QgZm9yIE1CTyBwcmVkaWN0ZWQgSUQgdG8gbWFrZSB0aGUgbmV4dCBwcmVkaWN0aW9uCnNldS5xJE1CT0FJVy5wcmVkIDwtIElkZW50cyhzZXUucSkKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnTUJPQUlXLnByZWQnLCBsYWJlbCA9IFRSVUUpCiAKIyMgY2hlY2sgdGhlIHByb3BvcnRpb24gb2YgY2VsbCB0eXBlcyBwcmVkaWN0ZWQgaW4gZWFjaCBjbHVzdGVyCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRwcmVkaWN0ZWQuaWQpKQpwci50LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHByb3AudGFibGUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRwcmVkaWN0ZWQuaWQpKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKCgojIHRyeSBiYXIgY2hhcnQKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKQoKIyB0aGUgcHJlZGljdGVkIGNlbGwgdHlwZXMgbWFrZSBtb3JlIHNlbnNlIGZyb20gdGhlIEFJVzAwMiBvcmdhbm9pZAojIG5vdyBwcmVkaWN0IHdpdGggdGhlIEFJVzAwMiA2MCBkYXlzIG9yZ2Fub2lkCgpJZGVudHMoQUlXNjApIDwtICJjbHVzdGVyLmlkcyIKRGVmYXVsdEFzc2F5KEFJVzYwKSA8LSAiUk5BIgoKYW5jaG9ycyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKHJlZmVyZW5jZSA9IEFJVzYwLCBxdWVyeSA9IHNldS5xLCBkaW1zID0gMToyNSkKcHJpbnQoImdldHRpbmcgcHJlZGljdGlvbnMiKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IEFJVzYwJGNsdXN0ZXIuaWRzKSAKc2V1LnEgPC0gQWRkTWV0YURhdGEoc2V1LnEsIG1ldGFkYXRhID0gcHJlZGljdGlvbnMpCnByaW50KHRhYmxlKHNldS5xJHByZWRpY3RlZC5pZCkpCgpJZGVudHMoc2V1LnEpIDwtICdwcmVkaWN0ZWQuaWQnCiMgYWRkIG5ldyBkYXRhc2xvdCBmb3IgTUJPIHByZWRpY3RlZCBJRCB0byBtYWtlIHRoZSBuZXh0IHByZWRpY3Rpb24Kc2V1LnEkQUlXNjAucHJlZCA8LSBJZGVudHMoc2V1LnEpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ0FJVzYwLnByZWQnLCBsYWJlbCA9IFRSVUUpCiAKIyMgY2hlY2sgdGhlIHByb3BvcnRpb24gb2YgY2VsbCB0eXBlcyBwcmVkaWN0ZWQgaW4gZWFjaCBjbHVzdGVyCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRwcmVkaWN0ZWQuaWQpKQpwci50LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHByb3AudGFibGUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRwcmVkaWN0ZWQuaWQpKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKCiMgdHJ5IGJhciBjaGFydApnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpCgojIHNhdmUgb2piZWN0IHdpdGggcHJlZGljaXRvbnMKc2F2ZVJEUyhzZXUucSwgIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BoZW5vSUQvc2NSTkFzZXFTb3J0ZWQvb2Jqcy9OZXVyb25zMlByZWRpY3Rpb25zU2V1MzAwOTIwMjIuUkRTIikKCgoKYGBgCgoKTG9vayBhdCB0aGUgY2VsbCB0eXBlIHByZWRpY3Rpb25zIGluIGVhY2ggY2x1c3RlciAtIE5ldXJvbnMgMQoKYGBge3J9CiMgQUlXMDAyIDE2MCBkYXlzIHByZWRpY3Rpb25zCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC42LCBzZXUucSRNQk9BSVcucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5jZWxsdHlwZS5BSVcxMjAgPC0gYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oMSwgRnJlcSkpCgojIEFJVzAwMiAxNjAgZGF5cyBwcmVkaWN0aW9ucwp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuNiwgc2V1LnEkQUlXNjAucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5jZWxsdHlwZS5BSVc2MCA8LWFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDEsIEZyZXEpKQoKIyBBU1QyMyA2NSBkYXlzIHByZWRpY3Rpb25zCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC42LCBzZXUucSRNQk9BU1QyMy5wcmVkKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKSArIFJvdGF0ZWRBeGlzKCkgCnRvcC5wcmVkLmNlbGx0eXBlLkFTVDIzIDwtIGFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDEsIEZyZXEpKQoKCnByZWQudGFibGUgPC0gbWVyZ2UodG9wLnByZWQuY2VsbHR5cGUuQUlXMTIwLHRvcC5wcmVkLmNlbGx0eXBlLkFJVzYwLCBieSA9ICdWYXIxJykKcHJlZC50YWJsZSA8LSBtZXJnZShwcmVkLnRhYmxlLCB0b3AucHJlZC5jZWxsdHlwZS5BU1QyMywgYnkgPSAnVmFyMScpCnByZWQudGFibGUKCmBgYAoKQmFzZWQgb24gdGhlIDMgZGlmZmVyZW50IHByZWRpY3Rpb25zIEkgY2FuIGxhYmxlIHRoZSBjZWxsIHR5cGVzCgowIC0gTlBDIG9yIGVhcmx5IG5ldXJvbnMKMSAtIGltbWF0dXJlIGV4Y2l0YXRvcnkgbmV1cm9ucwoyIC0gTlBDIG9yIGVhcmx5IG5ldXJvbnMKMyAtIFJHIG9yIE9saWdvcwo0LSBEb3BhbWluZXJnaWMgbmV1cm9ucyAtIHBvc3NpYmx5IGVhcmx5CjUgLSBOUEMgb3IgZWFybHkgbmV1cm9ucwo2IC0gUmFkaWFsIEdMaWEKClByZWRpY3Rpb25zIHdpdGggdGhlIERBIHN1YnR5cGVzIGZyb20gCgpgYGB7cn0KIyByZWFkIGluIHRoZSAKc2V1LnEgPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUGhlbm9JRC9zY1JOQXNlcVNvcnRlZC9vYmpzL05ldXJvbjFMYWJsZWRTZXUzMDA5MjAyMi5SRFMiKQoKRGltUGxvdChzZXUucSkKCmBgYAoKVXNlIHRoZSBCaGFkdXJpIGRhdGFzZXQKCmBgYHtyfQoKIyByZWFkIGluIHRoZSByZWZlcmVuY2UgZGF0YXNldAojIGZyb20gQmhhZHVyaSBtaWRicmFpbiBhbmQgc3RyaWF0dW0Kc2V1LnIgPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUHVibGljRGF0YS9CaGFkdXJpX3dob2xlQnJhaW4vQmhhZHVyaV9taWRicmFpbl9zdHJpYXR1bS5SRFMiKQp0YWJsZShzZXUuciRjZWxsX3R5cGUpCnRhYmxlKHNldS5yJGNlbGxfY2xhc3MpCnRhYmxlKHNldS5yJGNlbGxfY2x1c3RlcikKCklkZW50cyhzZXUucikgPC0gImNlbGxfY2x1c3RlciIKCiMgZmluZCB0aGUgcmVmZXJlbmNlIGFuY2hvcnMKYW5jaG9ycyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKHJlZmVyZW5jZSA9IHNldS5yLCBxdWVyeSA9IHNldS5xLCBkaW1zID0gMToyNSkKcHJpbnQoImdldHRpbmcgcHJlZGljdGlvbnMiKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IHNldS5yJGNlbGxfY2x1c3RlcikKc2V1LnEgPC0gQWRkTWV0YURhdGEoc2V1LnEsIG1ldGFkYXRhID0gcHJlZGljdGlvbnMpCnByaW50KHRhYmxlKHNldS5xJHByZWRpY3RlZC5pZCkpCgpJZGVudHMoc2V1LnEpIDwtICdwcmVkaWN0ZWQuaWQnCnNldS5xJEJoYS5taWQuc3RyaS5wcmVkIDwtIElkZW50cyhzZXUucSkKcHJpbnQodGFibGUoc2V1LnEkQmhhLm1pZC5zdHJpLnByZWQpKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdCaGEubWlkLnN0cmkucHJlZCcpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ3N1Ymdyb3VwcycpCgojIGRvIHRoZSBwcmVkaWN0aW9ucyBkaWZmZXIgd2l0aCB0aGUgbWFpbiBjZWxsIHR5cGUgZ3JvdXBzIGluc3RlYWQgb2YgdGhlIGNsdXN0ZXIgaW4gdGhlIHJlZmVyZW5jZSBkYXRhPyAKSWRlbnRzKHNldS5yKSA8LSAiY2VsbF90eXBlIgoKIyBmaW5kIHRoZSByZWZlcmVuY2UgYW5jaG9ycwphbmNob3JzIDwtIEZpbmRUcmFuc2ZlckFuY2hvcnMocmVmZXJlbmNlID0gc2V1LnIsIHF1ZXJ5ID0gc2V1LnEsIGRpbXMgPSAxOjI1KQpwcmludCgiZ2V0dGluZyBwcmVkaWN0aW9ucyIpCnByZWRpY3Rpb25zIDwtIFRyYW5zZmVyRGF0YShhbmNob3JzZXQgPSBhbmNob3JzLCByZWZkYXRhID0gc2V1LnIkY2VsbF90eXBlKQpzZXUucSA8LSBBZGRNZXRhRGF0YShzZXUucSwgbWV0YWRhdGEgPSBwcmVkaWN0aW9ucykKcHJpbnQodGFibGUoc2V1LnEkcHJlZGljdGVkLmlkKSkKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAncHJlZGljdGVkLmlkJykKCiMgZ29vZCBsYXJnZXN0IHByZWRpY3Rpb24gaXMgbmV1cm9ucy4gCgoKCmBgYAoKCgoKCkkgd2lsbCBhbHNvIGZpbmQgbWFya2VycyBhbmQgbG9vayBhdCBhIGxpc3Qgb2YgbmV1cm9uYWwgbWFya2VycwoKYGBge3J9CgpJZGVudHMoc2V1LnEpIDwtICdSTkFfc25uX3Jlcy4wLjYnCkNsdXN0ZXJNYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKHNldS5xLCBvbmx5LnBvcyA9IFRSVUUpCgp0b3A1IDwtIENsdXN0ZXJNYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24obj01LCB3dCA9IGF2Z19sb2cyRkMpCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSB0b3A1JGdlbmUsIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMiwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC42JykKCndyaXRlLmNzdihDbHVzdGVyTWFya2VycywiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUGhlbm9JRC9zY1JOQXNlcVNvcnRlZC9OZXVyb25zMUNsdXN0ZXJNYXJrZXJzNy5jc3YiKQoKCmBgYAoKRXhwbG9yZSBzb21lIEdlbmUgZXhwcmVzc2lvbiBsZXZlbHMKCmBgYHtyfQpmZWF0dXJlX2xpc3QgPSBjKCJNS0k2NyIsIlNPWDIiLCJQT1U1RjEiLCJETFgyIiwiUEFYNiIsIlNPWDkiLCJIRVMxIiwiTkVTIiwiUkJGT1gzIiwiTUFQMiIsIk5DQU0xIiwiQ0QyNCIsIkdSSUEyIiwiR1JJTjJCIiwiR0FCQlIxIiwiR0FEMSIsIkdBRDIiLCJHQUJSQTEiLCJHQUJSQjIiLCJUSCIsIkFMREgxQTEiLCJMTVgxQiIsIk5SNEEyIiwiQ09SSU4iLCJDQUxCMSIsIktDTko2IiwiQ1hDUjQiLCJJVEdBNiIsIlNMQzFBMyIsIkNENDQiLCJBUVA0IiwiUzEwMEIiLCAiUERHRlJBIiwiT0xJRzIiLCJNQlAiLCJDTEROMTEiLCJWSU0iLCJWQ0FNMSIpCgpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gZmVhdHVyZV9saXN0LCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIsIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjAuNicpCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gZmVhdHVyZV9saXN0KSArUm90YXRlZEF4aXMoKQoKUERfcG91bGluID0gYygiVEgiLCJTTEM2QTMiLCJTTEMxOEEyIiwiU09YNiIsIk5ETkYiLCJTTkNHIiwiQUxESDFBMSIsIkNBTEIxIiwiVEFDUjIiLCJTTEMxN0E2IiwiU0xDMzJBMSIsIk9UWDIiLCJHUlAiLCJMUEwiLCJDQ0siLCJWSVAiKQoKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IFBEX3BvdWxpbiwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjYnKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IFBEX3BvdWxpbikrUm90YXRlZEF4aXMoKQoKZWFscnlOZXVyID0gYygiRENYIiwiTkVVUk9EMSIsIlRCUjEiKQpwcm9saWZlcmF0aW9uID0gYygiUENOQSIsIk1LSTY3IikKbmV1cmFsc3RlbSA9IGMoIlNPWDIiLCJORVMiLCJQQVg2IiwiTUFTSDEiKQoKZmVhdHVyZV9saXN0IDwtIGMoIkRDWCIsIk5FVVJPRDEiLCJUQlIxIiwiUENOQSIsIk1LSTY3IiwiU09YMiIsIk5FUyIsIlBBWDYiLCJNQVNIMSIpCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBmZWF0dXJlX2xpc3QsIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMiwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC42JykKRG90UGxvdChzZXUucSwgZmVhdHVyZXMgPSBmZWF0dXJlX2xpc3QpK1JvdGF0ZWRBeGlzKCkKIyBubyBwcm9saWZlcmF0aW9uIG1hcmtlciBleHByZXNzaW9uICBQQ05BIG9yIE1LSTY3CiMgY2x1c3RlciA0IERBIG5ldXJvbnMgLSBzaG93cyBlYXJseSBuZXVyb24gbWFya2VyIGFuZCBsb3cgUEFYIDQKIyBjbHVzdGVyIDMgaGFzIGhpZ2hlciBTT1gyIC0gbmV1cm9ibGFzdCBtYXJrZXIgLyBOUEMgbWFya2VyCgptYXRfbmV1cm9uID0gYygiUkJGT1gzIiwiU1lQIiwiRExHNDUiLCJWQU1QMSIsIlZBTVAyIiwiVFVCQjMiLCJTWVQxIiwiQlNOIiwiSE9NRVIxIiwiU0xDMTdBNiIpIAojIE5ldU4gaXMgRk9YMyAtIFJCRk9YMwojIFBTRDk1IGFsc28gU1AtOTAgb3IgRExHNAojIFZHTFVUMiBpcyBTTEMxN0E2CkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBtYXRfbmV1cm9uLCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIsIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjAuNicpCiMgY2x1c3RlciA0IGFsc28gc2hvdyBtYXR1cmUgbmV1cm9uIG1hcmtlcnMKRG90UGxvdChzZXUucSwgZmVhdHVyZXMgPSBtYXRfbmV1cm9uKStSb3RhdGVkQXhpcygpCiMgZXhjaXRhdG9yeSBuZXVyb24gbWFya2VycwpleCA9IGMoIkdSSUEyIiwiR1JJQTEiLCJHUklBNCIsIkdSSU4xIiwiR1JJTjJCIiwiR1JJTjJBIiwiR1JJTjNBIiwiR1JJTjMiLCJHUklQMSIsIkNBTUsyQSIpCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBleCwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjYnKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IGV4KStSb3RhdGVkQXhpcygpCiMgaW5oaWJpdG9yeSBuZXVyb24gbWFya2VycwppbmggPSBjKCJHQUQxIiwiR0FEMiIsICJHQVQxIiwiUFZBTEIiLCJHQUJSMiIsIkdBQlIxIiwiR0JSUjEiLCJHQUJSQjIiLCJHQUJSQjEiLCJHQUJSQjMiLCJHQUJSQTYiLCJHQUJSQTEiLCJHQUJSQTQiLCJUUkFLMiIpCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBpbmgsIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMiwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC42JykKRG90UGxvdChzZXUucSwgZmVhdHVyZXMgPSBpbmgpK1JvdGF0ZWRBeGlzKCkKIyBjbHVzdGVyIDQgaXMgbW9yZSBleGNpdGF0b3J5IHRoYW4gaW5oYml0b3J5IGJ1dCBuZWl0aGVyIG1hcmtlciBzZXQgaGFzIG11Y2ggZXhwcmVzc2lvbiAKCgoKYGBgCgoKQ2hlY2tvdXQgdGhlIEVucmljaGVyIGNlbGwgdHlwZSBsaWJyYXJpZXMgZnJvbSAKCmBgYHtyfQojIHRlc3QgbWFya2VycyBmb3IgdGhlIDcgY2x1c3RlcnMgaW4gTmV1cm9uczEgCgpsaWJyYXJ5KGRldnRvb2xzKQppbnN0YWxsX2dpdGh1Yigid2phd2FpZC9lbnJpY2hSIikKbGlicmFyeShlbnJpY2hSKQoKCnNldEVucmljaHJTaXRlKCJFbnJpY2hyIikgIyBIdW1hbiBnZW5lcwojIGxpc3Qgb2YgYWxsIHRoZSBkYXRhYmFzZXMKCmRicyA8LSBsaXN0RW5yaWNockRicygpCmRicwojIGxpYmFyaWVzIHdpdGggY2VsbCB0eXBlcwoKZGIgPC0gYygnQWxsZW5fQnJhaW5fQXRsYXNfdXAnLCdEZXNjYXJ0ZXNfQ2VsbF9UeXBlc19hbmRfVGlzc3VlXzIwMjEnLAogICAgICAgICdDZWxsTWFya2VyX0F1Z21lbnRlZF8yMDIxJywnQXppbXV0aF9DZWxsX1R5cGVzXzIwMjEnKQoKIyBlbnJpY2hyKGdlbmVzLCBkYXRhYmFzZXMgPSBOVUxMKQoKTjEuYzAgPC0gQ2x1c3Rlck1hcmtlcnMgJT4lIGZpbHRlcihjbHVzdGVyID09IDAgJiBhdmdfbG9nMkZDID4gMCkKZ2VuZXMgPC0gTjEuYzAkZ2VuZQoKTjEuYzAuRXIgPC0gZW5yaWNocihnZW5lcywgZGF0YWJhc2VzID0gZGIpCnBsb3RFbnJpY2goTjEuYzAuRXJbWzFdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCnBsb3RFbnJpY2goTjEuYzAuRXJbWzJdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCnBsb3RFbnJpY2goTjEuYzAuRXJbWzNdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCgpOMS5Fci5nZW5lcy4xIDwtIE4xLmMwLkVyW1sxXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjEKCk4xLkVyLmdlbmVzLjIgPC0gTjEuYzAuRXJbWzJdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMgoKTjEuRXIuZ2VuZXMuMyA8LSBOMS5jMC5FcltbM11dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4zCgojIGNsdXN0ZXIgMCBjb3VsZCBiZSBoeXBvdGhhbG11cywgREEgbmV1cm9ucyBBMTMKCk4xLmMxIDwtIENsdXN0ZXJNYXJrZXJzICU+JSBmaWx0ZXIoY2x1c3RlciA9PSAxICYgYXZnX2xvZzJGQyA+IDApCmdlbmVzIDwtIE4xLmMxJGdlbmUKCk4xLmMxLkVyIDwtIGVucmljaHIoZ2VuZXMsIGRhdGFiYXNlcyA9IGRiKQpwbG90RW5yaWNoKE4xLmMxLkVyW1sxXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMxLkVyW1syXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMxLkVyW1szXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMxLkVyW1s0XV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQoKTjEuRXIuZ2VuZXMuMSA8LSBOMS5jMS5FcltbMV1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4xCgpOMS5Fci5nZW5lcy4yIDwtIE4xLmMxLkVyW1syXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjIKCk4xLkVyLmdlbmVzLjMgPC0gTjEuYzEuRXJbWzNdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMwoKTjEuRXIuZ2VuZXMuNCA8LSBOMS5jMS5FcltbNF1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy40CgojIGNsdXN0ZXIgMTsgb2xmYWN0b3J5IGJ1bGIsIG5ldXJhbCBwbGF0ZSwgbWF5YmUgUmFkaWFsIEdsaWEsIApOMS5jMiA8LSBDbHVzdGVyTWFya2VycyAlPiUgZmlsdGVyKGNsdXN0ZXIgPT0gMiAmIGF2Z19sb2cyRkMgPiAwKQpnZW5lcyA8LSBOMS5jMiRnZW5lCgpOMS5jMi5FciA8LSBlbnJpY2hyKGdlbmVzLCBkYXRhYmFzZXMgPSBkYikKcGxvdEVucmljaChOMS5jMi5FcltbMV1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKcGxvdEVucmljaChOMS5jMi5FcltbMl1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKcGxvdEVucmljaChOMS5jMi5FcltbM11dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKcGxvdEVucmljaChOMS5jMi5FcltbNF1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKCk4xLkVyLmdlbmVzLjEgPC0gTjEuYzIuRXJbWzFdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMQoKTjEuRXIuZ2VuZXMuMiA8LSBOMS5jMi5FcltbMl1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4yCgpOMS5Fci5nZW5lcy4zIDwtIE4xLmMyLkVyW1szXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjMKCk4xLkVyLmdlbmVzLjQgPC0gTjEuYzIuRXJbWzRdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuNAoKIyBjbHVzdGVyIDIgc29tZSBicmFpbiBudWNsZXVzLCBuZXVyYWwgc3RlbQoKTjEuYzMgPC0gQ2x1c3Rlck1hcmtlcnMgJT4lIGZpbHRlcihjbHVzdGVyID09IDMgJiBhdmdfbG9nMkZDID4gMCkKZ2VuZXMgPC0gTjEuYzMkZ2VuZQoKTjEuYzMuRXIgPC0gZW5yaWNocihnZW5lcywgZGF0YWJhc2VzID0gZGIpCnBsb3RFbnJpY2goTjEuYzMuRXJbWzFdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCnBsb3RFbnJpY2goTjEuYzMuRXJbWzJdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCnBsb3RFbnJpY2goTjEuYzMuRXJbWzNdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCnBsb3RFbnJpY2goTjEuYzMuRXJbWzRdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCgpOMS5Fci5nZW5lcy4xIDwtIE4xLmMzLkVyW1sxXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjEKCk4xLkVyLmdlbmVzLjIgPC0gTjEuYzMuRXJbWzJdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMgoKTjEuRXIuZ2VuZXMuMyA8LSBOMS5jMy5FcltbM11dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4zCgpOMS5Fci5nZW5lcy40IDwtIE4xLmMzLkVyW1s0XV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjQKCiMgY2x1c3RlciAzIHN0cm9tYWwgY2VsbCBvZiB0aHltdXMsIGVtYnJ5b25pYyBhc3Ryb2N5dGVzLCBPUEMsIE5LIGNlbGxzLCBtb25vY3l0ZXMKCk4xLmM0IDwtIENsdXN0ZXJNYXJrZXJzICU+JSBmaWx0ZXIoY2x1c3RlciA9PSA0ICYgYXZnX2xvZzJGQyA+IDApCmdlbmVzIDwtIE4xLmM0JGdlbmUKCk4xLmM0LkVyIDwtIGVucmljaHIoZ2VuZXMsIGRhdGFiYXNlcyA9IGRiKQpwbG90RW5yaWNoKE4xLmM0LkVyW1sxXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmM0LkVyW1syXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmM0LkVyW1szXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmM0LkVyW1s0XV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQoKTjEuRXIuZ2VuZXMuMSA8LSBOMS5jNC5FcltbMV1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4xCgpOMS5Fci5nZW5lcy4yIDwtIE4xLmM0LkVyW1syXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjIKCk4xLkVyLmdlbmVzLjMgPC0gTjEuYzQuRXJbWzNdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMwoKTjEuRXIuZ2VuZXMuNCA8LSBOMS5jNC5FcltbNF1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy40CgojIERlbnRhdGUgZ3lydXMgLSBkaWZmZXJlbnQgY29ydGljYWwgbGF5ZXJzLCBuZXVyb25zLCBuZXVyb25zLCBOUEMsIG5ldXJvbnMgR0FCQSxHTFVUCgpOMS5jNSA8LSBDbHVzdGVyTWFya2VycyAlPiUgZmlsdGVyKGNsdXN0ZXIgPT0gNSAmIGF2Z19sb2cyRkMgPiAwKQpnZW5lcyA8LSBOMS5jNSRnZW5lCgpOMS5jNS5FciA8LSBlbnJpY2hyKGdlbmVzLCBkYXRhYmFzZXMgPSBkYikKcGxvdEVucmljaChOMS5jNS5FcltbMV1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKcGxvdEVucmljaChOMS5jNS5FcltbMl1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKcGxvdEVucmljaChOMS5jNS5FcltbM11dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKcGxvdEVucmljaChOMS5jNS5FcltbNF1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKCk4xLkVyLmdlbmVzLjEgPC0gTjEuYzUuRXJbWzFdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMQoKTjEuRXIuZ2VuZXMuMiA8LSBOMS5jNS5FcltbMl1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4yCgpOMS5Fci5nZW5lcy4zIDwtIE4xLmM1LkVyW1szXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjMKCk4xLkVyLmdlbmVzLjQgPC0gTjEuYzUuRXJbWzRdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuNAoKIyBjbHVzdGVyIDUgaGlwcG9jYW1wdXMsIGVuZG90aGVsaWFsIGNlbGxzLCBwZXJpY3l0ZXMKCk4xLmM2IDwtIENsdXN0ZXJNYXJrZXJzICU+JSBmaWx0ZXIoY2x1c3RlciA9PSA2ICYgYXZnX2xvZzJGQyA+IDApCmdlbmVzIDwtIE4xLmM2JGdlbmUKCk4xLmM2LkVyIDwtIGVucmljaHIoZ2VuZXMsIGRhdGFiYXNlcyA9IGRiKQpwbG90RW5yaWNoKE4xLmM2LkVyW1sxXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmM2LkVyW1syXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmM2LkVyW1szXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmM2LkVyW1s0XV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQoKTjEuRXIuZ2VuZXMuMSA8LSBOMS5jNi5FcltbMV1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4xCgpOMS5Fci5nZW5lcy4yIDwtIE4xLmM2LkVyW1syXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjIKCk4xLkVyLmdlbmVzLjMgPC0gTjEuYzYuRXJbWzNdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMwoKTjEuRXIuZ2VuZXMuNCA8LSBOMS5jNi5FcltbNF1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy40CgojIGNsdXN0ZXIgNiBicmFpbiBjb3J0ZXgsIHNod2FubiBjZWxsLCBlbmRvdGhlbGlhbCwgcGVyaWN5dGUsIEdBQkEKCgpgYGAKCgpBZnRlciBwcmVkaWN0aW5nIHdpdGggdGhlIGJyYWluIGRhdGEgSSB0aGluayB1c2luZyBhIGhpZ2hlciBjbHVzdGVyIG51bWJlciB3aWxsIHdvcmsgYmV0dGVyCgoKYGBge3J9CgojIHJlczEuMiBoYXMgMTAgY2x1c3RlcnMKCgojIEFJVzAwMiAxMjAgZGF5cyBwcmVkaWN0aW9ucwp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjEuMiwgc2V1LnEkTUJPQUlXLnByZWQpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQUlXMTIwIDwtIGFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDIsIEZyZXEpKQpkZi50b3AuYWl3MTIwIDwtIHRvcC5wcmVkLmNlbGx0eXBlLkFJVzEyMFtvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5BSVcxMjAkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUuQUlXMTIwJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5haXcxMjApIDwtIE5VTEwKZGYudG9wLmFpdzEyMCRJIDwtIHJvdy5uYW1lcyhkZi50b3AuYWl3MTIwKQoKIyBBSVcwMDIgNjAgZGF5cyBwcmVkaWN0aW9ucwp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjEuMiwgc2V1LnEkQUlXNjAucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5jZWxsdHlwZS5BSVc2MCA8LWFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDIsIEZyZXEpKQpkZi50b3AuYWl3NjAgPC0gdG9wLnByZWQuY2VsbHR5cGUuQUlXNjBbb3JkZXIodG9wLnByZWQuY2VsbHR5cGUuQUlXNjAkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUuQUlXNjAkRnJlcSksXQpyb3cubmFtZXMoZGYudG9wLmFpdzYwKSA8LSBOVUxMCiMgc29tZXRoaW5nIHdlbnQgd3JvbmcgYW5kIHRoZXJlIGFyZSB0b28gbWFueSBjbHVzdGVyIDAgcHJlZGljdGlvbnMKZGYudG9wLmFpdzYwIDwtIGRmLnRvcC5haXc2MCAlPiUgIGZpbHRlcighcm93X251bWJlcigpICVpbiUgYygyLCAzLCA0KSkKZGYudG9wLmFpdzYwJEkgPC0gcm93Lm5hbWVzKGRmLnRvcC5haXc2MCkKCiMgQVNUMjMgMTY1IGRheXMgcHJlZGljdGlvbnMKdC5sYWJsZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4xLjIsIHNldS5xJE1CT0FTVDIzLnByZWQpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQVNUMjMgPC0gYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oMiwgRnJlcSkpCmRmLnRvcC5BU1QyMyA8LSB0b3AucHJlZC5jZWxsdHlwZS5BU1QyM1tvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5BU1QyMyRWYXIxLC10b3AucHJlZC5jZWxsdHlwZS5BU1QyMyRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3AuQVNUMjMpIDwtIE5VTEwKZGYudG9wLkFTVDIzJEkgPC0gcm93Lm5hbWVzKGRmLnRvcC5BU1QyMykKZGYudG9wLkFTVDIzIDwtIGRmLnRvcC5haXc2MCAlPiUgIGZpbHRlcighcm93X251bWJlcigpICVpbiUgYygyMikpCgojIyMgYWRkIGluIHRoZSBwcmVkaWN0aW9uIGZyb20gYnJhaW4gZGF0YSBCaGFkdXJpIG1pZGJyYWluIGFuZCBzdHJpYXR1bQp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjEuMiwgc2V1LnEkQmhhLm1pZC5zdHJpLnByZWQpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQmhhIDwtIGFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDIsIEZyZXEpKQpkZi50b3AuQmhhIDwtIHRvcC5wcmVkLmNlbGx0eXBlLkJoYVtvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5CaGEkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUuQmhhJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5CaGEpIDwtIE5VTEwKZGYudG9wLkJoYSRJIDwtIHJvdy5uYW1lcyhkZi50b3AuQmhhKQoKCnByZWQudGFibGUgPC0gbWVyZ2UoZGYudG9wLkFTVDIzLCBkZi50b3AuYWl3NjAsIGJ5ID0gJ0knLCBhbGwgPSBUUlVFKQpwcmVkLnRhYmxlIDwtIG1lcmdlKHByZWQudGFibGUsIGRmLnRvcC5haXcxMjAsIGJ5ID0gJ0knKQpwcmVkLnRhYmxlIDwtIG1lcmdlKHByZWQudGFibGUsIGRmLnRvcC5CaGEsIGJ5ID0gJ0knKQpwcmVkLnRhYmxlCgojIGNsdXN0ZXIgMyBpcyBwcmVkaWN0ZWQgYXMgT2xpZ28sIFJHLCBhc3RybwoKYGBgCgoKCgpMaWJyYXJ5IG9mIHRpc3N1ZSBjZWxsIHR5cGVzIGZvciB1cCByZWd1bGF0ZWQgZ2VuZXMgcGVyIGNsdXN0ZXIKMCAtIGh5cG90aGFsbXVzLCBEQSBBMTMKMS0gbmV1cmFsIHBsYXRlLCBSYWRpYWwgR2xpYQoyIC0gTmV1cmFsIHN0ZW0KMyAtIHN0cm9tYWwsIGFzdHJvIE9QQwo0IC0gTmV1cm9ucwo1IC0gZW5kb3RoZWxpYWwsIHBlcmljeXRlCjYgLSBtYXliZSBuZXVyb25zIG1heWJlIG5vdAoKCgoKCgpCeSB0aGUgY29tYmluZWQgaW5mb3JtYXRpb24gLSBhbm5vdGF0ZSB0aGUgY2x1c3RlcnMgaW4gTmV1cm9uczEKCmBgYHtyfQojQmFzZWQgb24gdGhlIDMgZGlmZmVyZW50IHByZWRpY3Rpb25zIEkgY2FuIGxhYmxlIHRoZSBjZWxsIHR5cGVzCgojMCAtIE5QQyBvciBlYXJseSBuZXVyb25zCiMxIC0gaW1tYXR1cmUgZXhjaXRhdG9yeSBuZXVyb25zCiMyIC0gTlBDIG9yIGVhcmx5IG5ldXJvbnMKIzMgLSBSRyBvciBPbGlnb3MKIzQtIERvcGFtaW5lcmdpYyBuZXVyb25zIC0gcG9zc2libHkgZWFybHkKIzUgLSBOUEMgb3IgZWFybHkgbmV1cm9ucwojNiAtIFJhZGlhbCBHbGlhCgpJZGVudHMoc2V1LnEpIDwtICdSTkFfc25uX3Jlcy4wLjYnCmNsdXN0ZXIuaWRzIDwtIGMoIkltbWF0dXJlTmV1cm9ucyIsIk5ldXJvbnMiLCJOUEMiLCJPUEMtUkciLCJEQW5ldXJvbnMiLAogICAgICAgICAgICAgICAgICJPdGhlciIsIlJHIikKdW5pcXVlKHNldS5xJFJOQV9zbm5fcmVzLjAuNikKCm5hbWVzKGNsdXN0ZXIuaWRzKSA8LSBsZXZlbHMoc2V1LnEpCnNldS5xIDwtIFJlbmFtZUlkZW50cyhzZXUucSwgY2x1c3Rlci5pZHMpCnNldS5xJHN1Ymdyb3VwcyA8LSBJZGVudHMoc2V1LnEpCgpEaW1QbG90KHNldS5xLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgZ3JvdXAuYnkgPSAnc3ViZ3JvdXBzJywgcmVwZWwgPSBUUlVFKQoKCnNhdmVSRFMoc2V1LnEsICIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QaGVub0lEL3NjUk5Bc2VxU29ydGVkL29ianMvTmV1cm9uMUxhYmxlZFNldTMwMDkyMDIyLlJEUyIpCgoKCmBgYAoKYGBge3J9CmxpYnJhcnkoY2x1c3RyZWUpCmNsdXN0cmVlKHNldS5xKQoKYGBgCgoKCgpBZnRlciBwcmVkaWN0aW5nIHdpdGggdGhlIGJyYWluIGRhdGEgQmhhZHVyaSBNaWRicmFpbiBhbmQgU3RyaWF0dW0gLSBjaG9vc2UgbWFpbiBjZWxsIHR5cGVzIHRvIGxhYmVsClRyaWVkIHRoZSBwcmVkaWN0aW9ucyB3aXRoIG1vcmUgY2x1c3RlcnMgMC05IHJlcyAxLjIKCmBgYHtyfQoKCiMwIC0gTlBDIG9yIGVhcmx5IG5ldXJvbnMgICAgICAgICAgPSAwLDcsMgojMSAtIGltbWF0dXJlIGV4Y2l0YXRvcnkgbmV1cm9ucyA9IDEsOAojMiAtIE5QQyBvciBlYXJseSBuZXVyb25zICAgICAgICAgPSA0LDYKIzMgLSBSRyBvciBPbGlnb3MgICAgICAgICAgICAgICAgIDksMiw3CiM0LSBEb3BhbWluZXJnaWMgbmV1cm9ucyAtIHBvc3NpYmx5IGVhcmx5ICAgPSAzCiM1IC0gTlBDIG9yIGVhcmx5IG5ldXJvbnMgICA9IDUKIzYgLSBSYWRpYWwgR2xpYSAgID0gOSAKCgojIDAgLSBuZXVyb25zIChOUEMpCiMgMSAtIG5ldXJvbnMgKE5QQykKIyAyIC0gYXN0cm8gKE5QQykKIyAzIC0gbmV1cm9ucyAoREEpCiMgNCAtIG5ldXJvbnMgKE5QQykKIyA1IC0gRW5kb3RoZWxpYWwgKHByZWRpY3RlZCBmcm9tIEJoYSwgcHJlZGljdGVkIGFzIE5QQykKIyA2IC0gTmV1cm9ucy8gR2xpYQojIDcgLSBBc3Ryb2N5dGVzIFJHCiMgOCAtIE5ldXJvbnMKIyA5IC0gRW5kb3RoZWxpYWwgUkcsIG5ldXJvbnMKCklkZW50cyhzZXUucSkgPC0gJ1JOQV9zbm5fcmVzLjEuMicKY2x1c3Rlci5pZHMgPC0gYygiTmV1cm9ucyIsIk5ldXJvbnMiLCJOZXVyb25zIiwiTmV1cm9ucyIsIk5ldXJvbnMiLAogICAgICAgICAgICAgICAgICJFbmRvdGhlbGlhbCIsIk5ldXJvbnMiLCJHbGlhIiwiTmV1cm9ucyIsIlJhZGlhbCBHbGlhIikKdW5pcXVlKHNldS5xJFJOQV9zbm5fcmVzLjAuNikKCm5hbWVzKGNsdXN0ZXIuaWRzKSA8LSBsZXZlbHMoc2V1LnEpCnNldS5xIDwtIFJlbmFtZUlkZW50cyhzZXUucSwgY2x1c3Rlci5pZHMpCnNldS5xJENlbGxfVHlwZXMgPC0gSWRlbnRzKHNldS5xKQoKRGltUGxvdChzZXUucSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIGdyb3VwLmJ5ID0gJ0NlbGxfVHlwZXMnLCByZXBlbCA9IFRSVUUpCgpzYXZlUkRTKHNldS5xLCAiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUGhlbm9JRC9zY1JOQXNlcVNvcnRlZC9vYmpzL05ldXJvbjFMYWJsZWRTZXUzMDA5MjAyMi5SRFMiKQoKCmBgYAoKCgoKCgoKCiMjIyBOZXh0IFJlcGVhdCBldmVyeXRoaW5nIGZvciBOZXVyb25zMgoKYGBge3J9CiMgZXhwbG9yZSBmaWx0ZXJpbmcKc2V1IDwtIE5ldXJvbnMyCnNldQpWbG5QbG90KHNldSwgcHQuc2l6ZSA9IDAuMTAsIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiwgIm5Db3VudF9STkEiLCAicGVyY2VudC5tdCIpLCBuY29sID0gMykKClZsblBsb3Qoc2V1LCBwdC5zaXplID0gMC4xMCwgZmVhdHVyZXMgPSBjKCJuRmVhdHVyZV9STkEiKSwgeS5tYXggPSAyMDAwKQpWbG5QbG90KHNldSwgcHQuc2l6ZSA9IDAuMTAsIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiksIHkubWF4ID0gMzUwKQpWbG5QbG90KHNldSwgcHQuc2l6ZSA9IDAuMTAsIGZlYXR1cmVzID0gYygibkNvdW50X1JOQSIpLCB5Lm1heCA9IDIwMDApCgojIGZpbHRlciBtb3JlIGNlbGxzCgpzZXUuZnQgPC0gc3Vic2V0KHNldSwgc3Vic2V0ID0gbkZlYXR1cmVfUk5BID4gMzAwICYgbkNvdW50X1JOQSA+IDUwMCAmIG5Db3VudF9STkEgPCAxMDAwMCkgCnNldS5mdAoKIyAxNzYwNCBzYW1wbGVzIHdpdGggMjUwIG5GZWF0dXJlX1JOQQojIDk2NTcgd2l0aCAgbkZlYXR1cmUgMzAwIGFuZCBuQ091bnQgNTAwCgoKYGBgCgoKRG91YmxldCBmaW5kZXIgCgpgYGB7cn0Kc3VwcHJlc3NNZXNzYWdlcyhyZXF1aXJlKERvdWJsZXRGaW5kZXIpKQoKIyBmaWx0ZXJpbmcgb3V0IE1BTEFUMSBhbmQgbWl0b2Nob25kcmlhbCBnZW5lcwoKc2V1LmZ0IDwtIHNldS5mdFshZ3JlcGwoIk1BTEFUMSIsIHJvd25hbWVzKHNldSkpLCBdCnNldS5mdCA8LSBzZXUuZnRbIWdyZXBsKCJeTVQtIiwgcm93bmFtZXMoc2V1LmZ0KSksIF0KCiMgbGlrZSBpbiB0aGUgdHV0b3JpYWwgSSdtIGZvbGxvd2luZyBNQUxBVDEgaXMgdGhlIHRvcCBtb3N0IGV4cHJlc3NlZCBnZW5lLiAgVGhlIHRvcCBnZW5lcyBhcmUgYSBsb3Qgb2YgTVQgYW5kIFJpYm9zb21hbCBnZW5lcwoKc2V1LmZ0W1sicGVyY2VudC5yYiJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChzZXUuZnQsIHBhdHRlcm4gPSAiXlJQIikKCnNldS5kID0gTm9ybWFsaXplRGF0YShzZXUuZnQpCnNldS5kID0gRmluZFZhcmlhYmxlRmVhdHVyZXMoc2V1LmQsIHZlcmJvc2UgPSBGKQpzZXUuZCA9IFNjYWxlRGF0YShzZXUuZCwgdmFycy50by5yZWdyZXNzID0gYygibkZlYXR1cmVfUk5BIiwgInBlcmNlbnQubXQiKSwKICAgIHZlcmJvc2UgPSBGKQpzZXUuZCA9IFJ1blBDQShzZXUuZCwgdmVyYm9zZSA9IEYsIG5wY3MgPSAzMCkKc2V1LmQgPSBSdW5VTUFQKHNldS5kLCBkaW1zID0gMToxMCwgdmVyYm9zZSA9IEYpCgpuRXhwIDwtIHJvdW5kKG5jb2woc2V1LmQpICogMC4wOCkgICMgZXhwZWN0IG1vcmUgZG91YmxldHMgYmVjYXVzZSB0aGVyZSBpcyBhIGxvdCBtb3JlIGNlbGxzCnNldS5kIDwtIGRvdWJsZXRGaW5kZXJfdjMoc2V1LmQsIHBOID0gMC4yNSwgcEsgPSAwLjA5LCBuRXhwID0gbkV4cCwgUENzID0gMToxMCkKCgojIG5hbWUgb2YgdGhlIERGIHByZWRpY3Rpb24gY2FuIGNoYW5nZSwgc28gZXh0cmFjdCB0aGUgY29ycmVjdCBjb2x1bW4gbmFtZS4KREYubmFtZSA9IGNvbG5hbWVzKHNldS5kQG1ldGEuZGF0YSlbZ3JlcGwoIkRGLmNsYXNzaWZpY2F0aW9uIiwgY29sbmFtZXMoc2V1LmRAbWV0YS5kYXRhKSldCgoKY293cGxvdDo6cGxvdF9ncmlkKG5jb2wgPSAyLCBEaW1QbG90KHNldS5kLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikgKyBOb0F4ZXMoKSwKICAgIERpbVBsb3Qoc2V1LmQsIGdyb3VwLmJ5ID0gREYubmFtZSkgKyBOb0F4ZXMoKSkKClZsblBsb3Qoc2V1LmQsIGZlYXR1cmVzID0gIm5GZWF0dXJlX1JOQSIsIGdyb3VwLmJ5ID0gREYubmFtZSwgcHQuc2l6ZSA9IDAuMSkKCmBgYAoKClJlbW92ZSB0aGUgZG91YmxldCBjZWxscwoKYGBge3J9CgpzZXUuZCA8LSBzZXUuZFssIHNldS5kQG1ldGEuZGF0YVssIERGLm5hbWVdPT0gIlNpbmdsZXQiXQpkaW0oc2V1LmQpCmRpbShzZXUpCiMgOTY1NyBjZWxscyBwcmUgZmlsdGVyCiMgODg4NCBjZWxscyBhZnRlciBmaWx0ZXJpbmcKIyBub3RlIHRoZSBwZXJjZW50IGRvdWJsZXMgZXhwZWN0ZWQgaXMgY2xvc2UgdG8gdGhlIHBlcmNlbnQgZGV0ZWN0ZWQKCmBgYAoKClJlcGVhdCB3b3JrZmxvdyB3aXRoIGRvdWJsZXQgcmVtb3ZlZCBkYXRhIGFuZCBmaW5kIGNsdXN0ZXJzIGZvciAKCmBgYHtyfQoKCnNldSA8LSBOb3JtYWxpemVEYXRhKHNldS5kLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCkKc2V1IDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKHNldSwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQpzZXUgPC0gU2NhbGVEYXRhKHNldSkKc2V1IDwtIFJ1blBDQShzZXUpCnNldSA8LSBSdW5VTUFQKHNldSwgcmVkdWN0aW9uID0gInBjYSIsIG4ubmVpZ2hib3JzID0gNDMsIGRpbXMgPSAxOjMwKQpEaW1QbG90KHNldSwgcmVkdWN0aW9uID0gInVtYXAiKQoKc2V1LnEgPC0gRmluZE5laWdoYm9ycyhzZXUsIGRpbXMgPSAxOjI1LCBrLnBhcmFtID0gNDMpCnNldS5xIDwtIEZpbmRDbHVzdGVycyhzZXUucSwgcmVzb2x1dGlvbiA9IGMoMCwwLjIsMC40LDAuNikpCgpsaWJyYXJ5KGNsdXN0cmVlKQpjbHVzdHJlZShzZXUucSkKCkRpbVBsb3Qoc2V1LnEsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC4yJykKRGltUGxvdChzZXUucSwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjQnKQpEaW1QbG90KHNldS5xLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjAuNicpCkRpbVBsb3Qoc2V1LnEsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMS4yJykKCmBgYAoKTGFiZWwgY2VsbCB0eXBlcyB1c2luZyB0aGUgbGFiZWwgdHJhbnNmZXIKCmBgYHtyfQoKCgojIFNOQ0EgYW5kIGNvbnRyb2wgbWlkYnJhaW4gb3JnYW5vaWRzIDE2NSBkYXlzIGluIGN1bHR1cmUKTUJPIDwtIHJlYWRSRFMoIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL0FTVDIzX0JyYWluQ29tbS9NQk9jbHVzdGVyc19uYW1lczI5MDcyMDIxLnJkcyIpCgojIE1pZGJyYWluICBBSVcwMDIgMTIwIGRheXMgaW4gY3VsdHVyZQpBSVdNQk8gPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvQUlXdHJpbzEyMGRheXMvTU9pbnRlZ3JhdGVkQ2x1c3RlcksxMjNyZXMwLjgubmFtZXNfbm92MTZfMjAyMSIpCgojIE1pZGJyYWluIEFJVzAwMiA2MCBkYXlzIGluIGN1bHR1cmUKCkFJVzYwIDwtIHJlYWRSRFMoIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL0FJV3RyaW82MGRheXMvQVdJMDAyUGFya2luS09QaW5rS082MGRheXNfbGFiZWxzXzE0MDUyMDIyLnJkcyIpCgoKIyBxdWVyeQojc2V1LnEgPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUGhlbm9JRC9zY1JOQXNlcVNvcnRlZC9vYmpzL05ldXJvbnNGaWx0ZXJlZFNldTI4MDkyMDIyLlJEUyIpCgoKI2ZpcnN0IHByZWRpY3Qgd2l0aCB0aGUgTUJPIGRhdGEKSWRlbnRzKE1CTykgPC0gImNsdXN0ZXJfbGFiZWxzIgpEZWZhdWx0QXNzYXkoTUJPKSA8LSAiUk5BIgoKIyBmaW5kIHRoZSByZWZlcmVuY2UgYW5jaG9ycwpwcmludCgiZmluZGluZyByZWZlcmVuY2UgYW5jaG9ycyIpCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBNQk8gLHF1ZXJ5ID0gc2V1LnEsIGRpbXMgPSAxOjI1KQpwcmludCgiZ2V0dGluZyBwcmVkaWN0aW9ucyIpCnByZWRpY3Rpb25zIDwtIFRyYW5zZmVyRGF0YShhbmNob3JzZXQgPSBhbmNob3JzLCByZWZkYXRhID0gTUJPJGNsdXN0ZXJfbGFiZWxzKQpzZXUucSA8LSBBZGRNZXRhRGF0YShzZXUucSwgbWV0YWRhdGEgPSBwcmVkaWN0aW9ucykKcHJpbnQodGFibGUoc2V1LnEkcHJlZGljdGVkLmlkKSkKCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKIyBhZGQgbmV3IGRhdGFzbG90IGZvciBNQk8gcHJlZGljdGVkIElEIHRvIG1ha2UgdGhlIG5leHQgcHJlZGljdGlvbgpzZXUucSRNQk9BU1QyMy5wcmVkIDwtIElkZW50cyhzZXUucSkKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnTUJPQVNUMjMucHJlZCcsIGxhYmVsID0gVFJVRSkKIAojIyBjaGVjayB0aGUgcHJvcG9ydGlvbiBvZiBjZWxsIHR5cGVzIHByZWRpY3RlZCBpbiBlYWNoIGNsdXN0ZXIKdC5sYWJsZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4wLjIsIHNldS5xJHByZWRpY3RlZC5pZCkpCnByLnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUocHJvcC50YWJsZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4wLjIsIHNldS5xJHByZWRpY3RlZC5pZCkpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQoKCiMgdHJ5IGJhciBjaGFydApnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpCgojIGNsdXN0ZXJzIGRvbid0IGJyZWFrIHVwIGJ5IHRoZSBwcmVkaWN0ZWQgY2VsbCB0eXBlcwoKIyMjIyMjIyMjIyMjIGFub3RoZXIgcHJlZGljdGlvbnMgbm93IHVzaW5nIHRoZSBBSVcgb3JnYW5vaWRzCgpJZGVudHMoQUlXTUJPKSA8LSAicmVzMDhuYW1lcyIKRGVmYXVsdEFzc2F5KEFJV01CTykgPC0gIlJOQSIKCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBBSVdNQk8gLHF1ZXJ5ID0gc2V1LnEsIGRpbXMgPSAxOjI1KQpwcmludCgiZ2V0dGluZyBwcmVkaWN0aW9ucyIpCnByZWRpY3Rpb25zIDwtIFRyYW5zZmVyRGF0YShhbmNob3JzZXQgPSBhbmNob3JzLCByZWZkYXRhID0gQUlXTUJPJHJlczA4bmFtZXMpCnNldS5xIDwtIEFkZE1ldGFEYXRhKHNldS5xLCBtZXRhZGF0YSA9IHByZWRpY3Rpb25zKQpwcmludCh0YWJsZShzZXUucSRwcmVkaWN0ZWQuaWQpKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwojIGFkZCBuZXcgZGF0YXNsb3QgZm9yIE1CTyBwcmVkaWN0ZWQgSUQgdG8gbWFrZSB0aGUgbmV4dCBwcmVkaWN0aW9uCnNldS5xJE1CT0FJVy5wcmVkIDwtIElkZW50cyhzZXUucSkKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnTUJPQUlXLnByZWQnLCBsYWJlbCA9IFRSVUUpCiAKIyMgY2hlY2sgdGhlIHByb3BvcnRpb24gb2YgY2VsbCB0eXBlcyBwcmVkaWN0ZWQgaW4gZWFjaCBjbHVzdGVyCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRwcmVkaWN0ZWQuaWQpKQpwci50LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHByb3AudGFibGUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRwcmVkaWN0ZWQuaWQpKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKCgojIHRyeSBiYXIgY2hhcnQKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKQoKIyB0aGUgcHJlZGljdGVkIGNlbGwgdHlwZXMgbWFrZSBtb3JlIHNlbnNlIGZyb20gdGhlIEFJVzAwMiBvcmdhbm9pZAojIG5vdyBwcmVkaWN0IHdpdGggdGhlIEFJVzAwMiA2MCBkYXlzIG9yZ2Fub2lkCgpJZGVudHMoQUlXNjApIDwtICJjbHVzdGVyLmlkcyIKRGVmYXVsdEFzc2F5KEFJVzYwKSA8LSAiUk5BIgoKYW5jaG9ycyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKHJlZmVyZW5jZSA9IEFJVzYwLCBxdWVyeSA9IHNldS5xLCBkaW1zID0gMToyNSkKcHJpbnQoImdldHRpbmcgcHJlZGljdGlvbnMiKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IEFJVzYwJGNsdXN0ZXIuaWRzKSAKc2V1LnEgPC0gQWRkTWV0YURhdGEoc2V1LnEsIG1ldGFkYXRhID0gcHJlZGljdGlvbnMpCnByaW50KHRhYmxlKHNldS5xJHByZWRpY3RlZC5pZCkpCgpJZGVudHMoc2V1LnEpIDwtICdwcmVkaWN0ZWQuaWQnCiMgYWRkIG5ldyBkYXRhc2xvdCBmb3IgTUJPIHByZWRpY3RlZCBJRCB0byBtYWtlIHRoZSBuZXh0IHByZWRpY3Rpb24Kc2V1LnEkQUlXNjAucHJlZCA8LSBJZGVudHMoc2V1LnEpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ0FJVzYwLnByZWQnLCBsYWJlbCA9IFRSVUUpCiAKIyMgY2hlY2sgdGhlIHByb3BvcnRpb24gb2YgY2VsbCB0eXBlcyBwcmVkaWN0ZWQgaW4gZWFjaCBjbHVzdGVyCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRwcmVkaWN0ZWQuaWQpKQpwci50LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHByb3AudGFibGUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRwcmVkaWN0ZWQuaWQpKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKCgojIHRyeSBiYXIgY2hhcnQKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKQoKIyBzYXZlIG9qYmVjdCB3aXRoIHByZWRpY2l0b25zCnNhdmVSRFMoc2V1LnEsICIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QaGVub0lEL3NjUk5Bc2VxU29ydGVkL29ianMvTmV1cm9uczJQcmVkaWN0aW9uc1NldTMwMDkyMDIyLlJEUyIpCgoKCmBgYAoKClByZWRpY3QgZnJvbSBCcmFpbiBCaGFoYW5pCgpgYGB7cn0KCnNldS5xIDwtIHJlYWRSRFMoIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BoZW5vSUQvc2NSTkFzZXFTb3J0ZWQvb2Jqcy9OZXVyb25zMkxhYmVsc1NldTMwMDkyMDIyLlJEUyIpCgoKIyByZWFkIGluIHRoZSByZWZlcmVuY2UgZGF0YXNldAojIGZyb20gQmhhZHVyaSBtaWRicmFpbiBhbmQgc3RyaWF0dW0Kc2V1LnIgPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUHVibGljRGF0YS9CaGFkdXJpX3dob2xlQnJhaW4vQmhhZHVyaV9taWRicmFpbl9zdHJpYXR1bS5SRFMiKQp0YWJsZShzZXUuciRjZWxsX3R5cGUpCnRhYmxlKHNldS5yJGNlbGxfY2xhc3MpCnRhYmxlKHNldS5yJGNlbGxfY2x1c3RlcikKCklkZW50cyhzZXUucikgPC0gImNlbGxfY2x1c3RlciIKCiMgZmluZCB0aGUgcmVmZXJlbmNlIGFuY2hvcnMKYW5jaG9ycyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKHJlZmVyZW5jZSA9IHNldS5yLCBxdWVyeSA9IHNldS5xLCBkaW1zID0gMToyNSkKcHJpbnQoImdldHRpbmcgcHJlZGljdGlvbnMiKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IHNldS5yJGNlbGxfY2x1c3RlcikKc2V1LnEgPC0gQWRkTWV0YURhdGEoc2V1LnEsIG1ldGFkYXRhID0gcHJlZGljdGlvbnMpCnByaW50KHRhYmxlKHNldS5xJHByZWRpY3RlZC5pZCkpCgpJZGVudHMoc2V1LnEpIDwtICdwcmVkaWN0ZWQuaWQnCnNldS5xJEJoYS5taWQuc3RyaS5wcmVkIDwtIElkZW50cyhzZXUucSkKcHJpbnQodGFibGUoc2V1LnEkQmhhLm1pZC5zdHJpLnByZWQpKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdCaGEubWlkLnN0cmkucHJlZCcpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ3N1Ymdyb3VwcycpCgojIGRvIHRoZSBwcmVkaWN0aW9ucyBkaWZmZXIgd2l0aCB0aGUgbWFpbiBjZWxsIHR5cGUgZ3JvdXBzIGluc3RlYWQgb2YgdGhlIGNsdXN0ZXIgaW4gdGhlIHJlZmVyZW5jZSBkYXRhPyAKSWRlbnRzKHNldS5yKSA8LSAiY2VsbF90eXBlIgoKIyBmaW5kIHRoZSByZWZlcmVuY2UgYW5jaG9ycwphbmNob3JzIDwtIEZpbmRUcmFuc2ZlckFuY2hvcnMocmVmZXJlbmNlID0gc2V1LnIsIHF1ZXJ5ID0gc2V1LnEsIGRpbXMgPSAxOjI1KQpwcmludCgiZ2V0dGluZyBwcmVkaWN0aW9ucyIpCnByZWRpY3Rpb25zIDwtIFRyYW5zZmVyRGF0YShhbmNob3JzZXQgPSBhbmNob3JzLCByZWZkYXRhID0gc2V1LnIkY2VsbF90eXBlKQpzZXUucSA8LSBBZGRNZXRhRGF0YShzZXUucSwgbWV0YWRhdGEgPSBwcmVkaWN0aW9ucykKcHJpbnQodGFibGUoc2V1LnEkcHJlZGljdGVkLmlkKSkKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAncHJlZGljdGVkLmlkJykKCiMgZ29vZCBsYXJnZXN0IHByZWRpY3Rpb24gaXMgbmV1cm9ucy4gCgoKYGBgCgoKClNlZSB0aGUgdG9wIHByZWRpY3Rpb25zIGZvciBlYWNoIGNsdXN0ZXIgaW4gTmV1cm9uczIgcmVzIDA2IAoKCmBgYHtyfQoKIyBBSVcwMDIgMTIwIGRheXMgcHJlZGljdGlvbnMKdC5sYWJsZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4wLjYsIHNldS5xJE1CT0FJVy5wcmVkKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKSArIFJvdGF0ZWRBeGlzKCkgCnRvcC5wcmVkLmNlbGx0eXBlLkFJVzEyMCA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLmFpdzEyMCA8LSB0b3AucHJlZC5jZWxsdHlwZS5BSVcxMjBbb3JkZXIodG9wLnByZWQuY2VsbHR5cGUuQUlXMTIwJFZhcjEsLXRvcC5wcmVkLmNlbGx0eXBlLkFJVzEyMCRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3AuYWl3MTIwKSA8LSBOVUxMCmRmLnRvcC5haXcxMjAgPC0gZGYudG9wLmFpdzEyMCAlPiUgIGZpbHRlcighcm93X251bWJlcigpICVpbiUgYygyMCwgMjEsIDIyLCAyMywgMjQpKQpkZi50b3AuYWl3MTIwJEkgPC0gcm93Lm5hbWVzKGRmLnRvcC5haXcxMjApCgojIEFJVzAwMiA2MCBkYXlzIHByZWRpY3Rpb25zCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC42LCBzZXUucSRBSVc2MC5wcmVkKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKSArIFJvdGF0ZWRBeGlzKCkgCnRvcC5wcmVkLmNlbGx0eXBlLkFJVzYwIDwtYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oMiwgRnJlcSkpCmRmLnRvcC5haXc2MCA8LSB0b3AucHJlZC5jZWxsdHlwZS5BSVc2MFtvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5BSVc2MCRWYXIxLC10b3AucHJlZC5jZWxsdHlwZS5BSVc2MCRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3AuYWl3NjApIDwtIE5VTEwKIyBzb21ldGhpbmcgd2VudCB3cm9uZyBhbmQgdGhlcmUgYXJlIHRvbyBtYW55IGNsdXN0ZXIgMCBwcmVkaWN0aW9ucwojZGYudG9wLmFpdzYwIDwtIGRmLnRvcC5haXc2MCAlPiUgIGZpbHRlcighcm93X251bWJlcigpICVpbiUgYygyLCAzLCA0KSkKZGYudG9wLmFpdzYwJEkgPC0gcm93Lm5hbWVzKGRmLnRvcC5haXc2MCkKCiMgQVNUMjMgMTY1IGRheXMgcHJlZGljdGlvbnMKdC5sYWJsZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4wLjYsIHNldS5xJE1CT0FTVDIzLnByZWQpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQVNUMjMgPC0gYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oMiwgRnJlcSkpCmRmLnRvcC5BU1QyMyA8LSB0b3AucHJlZC5jZWxsdHlwZS5BU1QyM1tvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5BU1QyMyRWYXIxLC10b3AucHJlZC5jZWxsdHlwZS5BU1QyMyRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3AuQVNUMjMpIDwtIE5VTEwKZGYudG9wLkFTVDIzIDwtIGRmLnRvcC5BU1QyMyAlPiUgIGZpbHRlcighcm93X251bWJlcigpICVpbiUgYygyMCwgMjEsIDIyLCAyMywgMjQsIDI1KSkKZGYudG9wLkFTVDIzJEkgPC0gcm93Lm5hbWVzKGRmLnRvcC5BU1QyMykKCiMjIyBhZGQgaW4gdGhlIHByZWRpY3Rpb24gZnJvbSBicmFpbiBkYXRhIEJoYWR1cmkgbWlkYnJhaW4gYW5kIHN0cmlhdHVtCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC42LCBzZXUucSRCaGEubWlkLnN0cmkucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5jZWxsdHlwZS5CaGEgPC0gYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oMiwgRnJlcSkpCmRmLnRvcC5CaGEgPC0gdG9wLnByZWQuY2VsbHR5cGUuQmhhW29yZGVyKHRvcC5wcmVkLmNlbGx0eXBlLkJoYSRWYXIxLC10b3AucHJlZC5jZWxsdHlwZS5CaGEkRnJlcSksXQpyb3cubmFtZXMoZGYudG9wLkJoYSkgPC0gTlVMTApkZi50b3AuQmhhJEkgPC0gcm93Lm5hbWVzKGRmLnRvcC5CaGEpCgoKcHJlZC50YWJsZSA8LSBtZXJnZShkZi50b3AuQVNUMjMsIGRmLnRvcC5haXc2MCwgYnkgPSAnSScsIGFsbCA9IFRSVUUpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLmFpdzEyMCwgYnkgPSAnSScpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLkJoYSwgYnkgPSAnSScpCnByZWQudGFibGUKCiMgY2x1c3RlciAzIGlzIHByZWRpY3RlZCBhcyBPbGlnbywgUkcsIGFzdHJvCgoKCgpgYGAKCgpgYGB7cn0KIyByZXMxLjIgaGFzIDE1IGNsdXN0ZXJzCgojIEFJVzAwMiAxMjAgZGF5cyBwcmVkaWN0aW9ucwp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjEuMiwgc2V1LnEkTUJPQUlXLnByZWQpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQUlXMTIwIDwtIGFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDIsIEZyZXEpKQpkZi50b3AuYWl3MTIwIDwtIHRvcC5wcmVkLmNlbGx0eXBlLkFJVzEyMFtvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5BSVcxMjAkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUuQUlXMTIwJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5haXcxMjApIDwtIE5VTEwKZGYudG9wLmFpdzEyMCA8LSBkZi50b3AuYWl3MTIwICU+JSAgZmlsdGVyKCFyb3dfbnVtYmVyKCkgJWluJSBjKDI2LCAyNywgMjgsIDI5LCAzMCkpCmRmLnRvcC5haXcxMjAkSSA8LSByb3cubmFtZXMoZGYudG9wLmFpdzEyMCkKCiMgQUlXMDAyIDYwIGRheXMgcHJlZGljdGlvbnMKdC5sYWJsZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4xLjIsIHNldS5xJEFJVzYwLnByZWQpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQUlXNjAgPC1hcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLmFpdzYwIDwtIHRvcC5wcmVkLmNlbGx0eXBlLkFJVzYwW29yZGVyKHRvcC5wcmVkLmNlbGx0eXBlLkFJVzYwJFZhcjEsLXRvcC5wcmVkLmNlbGx0eXBlLkFJVzYwJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5haXc2MCkgPC0gTlVMTAojIHNvbWV0aGluZyB3ZW50IHdyb25nIGFuZCB0aGVyZSBhcmUgdG9vIG1hbnkgY2x1c3RlciAwIHByZWRpY3Rpb25zCiNkZi50b3AuYWl3NjAgPC0gZGYudG9wLmFpdzYwICU+JSAgZmlsdGVyKCFyb3dfbnVtYmVyKCkgJWluJSBjKDIsIDMsIDQpKQpkZi50b3AuYWl3NjAkSSA8LSByb3cubmFtZXMoZGYudG9wLmFpdzYwKQoKIyBBU1QyMyAxNjUgZGF5cyBwcmVkaWN0aW9ucwp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjEuMiwgc2V1LnEkTUJPQVNUMjMucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5jZWxsdHlwZS5BU1QyMyA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLkFTVDIzIDwtIHRvcC5wcmVkLmNlbGx0eXBlLkFTVDIzW29yZGVyKHRvcC5wcmVkLmNlbGx0eXBlLkFTVDIzJFZhcjEsLXRvcC5wcmVkLmNlbGx0eXBlLkFTVDIzJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5BU1QyMykgPC0gTlVMTApkZi50b3AuQVNUMjMgPC0gZGYudG9wLkFTVDIzICU+JSAgZmlsdGVyKCFyb3dfbnVtYmVyKCkgJWluJSBjKDI2LCAyNywgMjgsIDI5LCAzMCwgMzEpKQpkZi50b3AuQVNUMjMkSSA8LSByb3cubmFtZXMoZGYudG9wLkFTVDIzKQoKCiMjIyBhZGQgaW4gdGhlIHByZWRpY3Rpb24gZnJvbSBicmFpbiBkYXRhIEJoYWR1cmkgbWlkYnJhaW4gYW5kIHN0cmlhdHVtCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMS4yLCBzZXUucSRCaGEubWlkLnN0cmkucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5jZWxsdHlwZS5CaGEgPC0gYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oMiwgRnJlcSkpCmRmLnRvcC5CaGEgPC0gdG9wLnByZWQuY2VsbHR5cGUuQmhhW29yZGVyKHRvcC5wcmVkLmNlbGx0eXBlLkJoYSRWYXIxLC10b3AucHJlZC5jZWxsdHlwZS5CaGEkRnJlcSksXQpyb3cubmFtZXMoZGYudG9wLkJoYSkgPC0gTlVMTApkZi50b3AuQmhhJEkgPC0gcm93Lm5hbWVzKGRmLnRvcC5CaGEpCgoKcHJlZC50YWJsZSA8LSBtZXJnZShkZi50b3AuQVNUMjMsIGRmLnRvcC5haXc2MCwgYnkgPSAnSScsIGFsbCA9IFRSVUUpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLmFpdzEyMCwgYnkgPSAnSScpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLkJoYSwgYnkgPSAnSScpCnByZWQudGFibGUKCiMgbmV1cm9ucyA5OCBtYXRjaGVzIHVwIHdpdGggREEgbmV1cm9ucwoKYGBgCgoKCgpXaGF0IGNlbGwgdHlwZXMgYXJlIHByZWRpY3RlZCBhY3Jvc3MgdGhlIDMgcmVmZXJlbmNlcwoKMCAtIE5ldXJvbnMgZWFybHkgLCBOUEMsIG5ldXJvbnMgZXhjaXRhdG9yeQoxIC0gTmV1cm9ucyBlYXJseSwgTlBDCjIgLSBOZXVyb25zIGVhcmx5LCBOUEMsIG5ldXJvbnMgZXhjaXRhdG9yeSBzb21lIERBIG5ldXJvbnMKMyAtIE9saWdvLCBSRywgCjQgLSBFeGNpdGF0b3J5IG5ldXJvbnMsIE5QQywgZWFybHkgbmV1cm9ucwo1IC0gREEgbmV1cm9ucywgZWFybHkgREEgbmV1cm9ucwo2IC0gbmV1cm9ucyBpbW1hdHVyZSBOUEMKNyAtIERBIG5ldXJvbnMKOCAtIFJHLCBvbGlnbywgT1BDLCBOUEMKOSAtIFJhZGlhbCBHbGlhCjEwIC0gTlBDLCBuZXVyb25zLCBvbGlnbwoxMSAtIE5QQywgbmV1cm9ucywgb2xpZ28KCgpGaW5kIGNsdXN0ZXIgbWFya2VycyBhbmQgc2VlIGhvdyB0aG9zZSB3b3VsZCBhbm5vdGF0ZQoKYGBge3J9CklkZW50cyhzZXUucSkgPC0gJ1JOQV9zbm5fcmVzLjAuNicKQ2x1c3Rlck1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoc2V1LnEsIG9ubHkucG9zID0gVFJVRSkKCnRvcDUgPC0gQ2x1c3Rlck1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuPTUsIHd0ID0gYXZnX2xvZzJGQykKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IHRvcDUkZ2VuZSwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjYnKQoKd3JpdGUuY3N2KENsdXN0ZXJNYXJrZXJzLCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QaGVub0lEL3NjUk5Bc2VxU29ydGVkL05ldXJvbnMxQ2x1c3Rlck1hcmtlcnMxMS5jc3YiKQoKYGBgCkNsdXN0ZXIgMCBoYXMgZmV3ZXIgbWFya2Vycy4gCjIgYW5kIDUgaGF2ZSBzaW1pbGFyIHVwIHJlZyBtYXJrZXJzCjMgYW5kIDQgYWxzbyBvdmVybGFwCgoKCkxvb2sgYXQgdGhlIGNsdXN0ZXIgbWFya2VycyBpbiBjZWxsIHR5cGUgbGlicmFyaWVzIGZvciBOZXVyb25zIDIKCmBgYHtyfQpsaWJyYXJ5KGVucmljaFIpCmRiIDwtIGMoJ0FsbGVuX0JyYWluX0F0bGFzX3VwJywnRGVzY2FydGVzX0NlbGxfVHlwZXNfYW5kX1Rpc3N1ZV8yMDIxJywKICAgICAgICAnQ2VsbE1hcmtlcl9BdWdtZW50ZWRfMjAyMScsJ0F6aW11dGhfQ2VsbF9UeXBlc18yMDIxJykKCiMgZW5yaWNocihnZW5lcywgZGF0YWJhc2VzID0gTlVMTCkKIyBjbHVzdGVyIDAKCk4xLmMwIDwtIENsdXN0ZXJNYXJrZXJzICU+JSBmaWx0ZXIoY2x1c3RlciA9PSAwICYgYXZnX2xvZzJGQyA+IDApCmdlbmVzIDwtIE4xLmMwJGdlbmUKCk4xLmMwLkVyIDwtIGVucmljaHIoZ2VuZXMsIGRhdGFiYXNlcyA9IGRiKQpwbG90RW5yaWNoKE4xLmMwLkVyW1sxXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMwLkVyW1syXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMwLkVyW1szXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQoKTjEuRXIuZ2VuZXMuMSA8LSBOMS5jMC5FcltbMV1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4xCgpOMS5Fci5nZW5lcy4yIDwtIE4xLmMwLkVyW1syXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjIKCk4xLkVyLmdlbmVzLjMgPC0gTjEuYzAuRXJbWzNdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMwoKIyBjbHVzdGVyIDEKCk4xLmMxIDwtIENsdXN0ZXJNYXJrZXJzICU+JSBmaWx0ZXIoY2x1c3RlciA9PSAxICYgYXZnX2xvZzJGQyA+IDApCmdlbmVzIDwtIE4xLmMxJGdlbmUKCk4xLmMxLkVyIDwtIGVucmljaHIoZ2VuZXMsIGRhdGFiYXNlcyA9IGRiKQpwbG90RW5yaWNoKE4xLmMxLkVyW1sxXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMxLkVyW1syXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMxLkVyW1szXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMxLkVyW1s0XV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQoKTjEuRXIuZ2VuZXMuMSA8LSBOMS5jMS5FcltbMV1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4xCgpOMS5Fci5nZW5lcy4yIDwtIE4xLmMxLkVyW1syXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjIKCk4xLkVyLmdlbmVzLjMgPC0gTjEuYzEuRXJbWzNdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMwoKTjEuRXIuZ2VuZXMuNCA8LSBOMS5jMS5FcltbNF1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy40CgojIGNsdXN0ZXIgMTsgb2xmYWN0b3J5IGJ1bGIsIG5ldXJhbCBwbGF0ZSwgbWF5YmUgUmFkaWFsIEdsaWEsIApOMS5jMiA8LSBDbHVzdGVyTWFya2VycyAlPiUgZmlsdGVyKGNsdXN0ZXIgPT0gMiAmIGF2Z19sb2cyRkMgPiAwKQpnZW5lcyA8LSBOMS5jMiRnZW5lCgpOMS5jMi5FciA8LSBlbnJpY2hyKGdlbmVzLCBkYXRhYmFzZXMgPSBkYikKcGxvdEVucmljaChOMS5jMi5FcltbMV1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKcGxvdEVucmljaChOMS5jMi5FcltbMl1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKcGxvdEVucmljaChOMS5jMi5FcltbM11dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKcGxvdEVucmljaChOMS5jMi5FcltbNF1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKCk4xLkVyLmdlbmVzLjEgPC0gTjEuYzIuRXJbWzFdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMQoKTjEuRXIuZ2VuZXMuMiA8LSBOMS5jMi5FcltbMl1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4yCgpOMS5Fci5nZW5lcy4zIDwtIE4xLmMyLkVyW1szXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjMKCk4xLkVyLmdlbmVzLjQgPC0gTjEuYzIuRXJbWzRdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuNAoKIyBjbHVzdGVyIDMKCk4xLmMzIDwtIENsdXN0ZXJNYXJrZXJzICU+JSBmaWx0ZXIoY2x1c3RlciA9PSAzICYgYXZnX2xvZzJGQyA+IDApCmdlbmVzIDwtIE4xLmMzJGdlbmUKCk4xLmMzLkVyIDwtIGVucmljaHIoZ2VuZXMsIGRhdGFiYXNlcyA9IGRiKQpwbG90RW5yaWNoKE4xLmMzLkVyW1sxXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMzLkVyW1syXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMzLkVyW1szXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMzLkVyW1s0XV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQoKTjEuRXIuZ2VuZXMuMSA8LSBOMS5jMy5FcltbMV1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4xCgpOMS5Fci5nZW5lcy4yIDwtIE4xLmMzLkVyW1syXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjIKCk4xLkVyLmdlbmVzLjMgPC0gTjEuYzMuRXJbWzNdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMwoKTjEuRXIuZ2VuZXMuNCA8LSBOMS5jMy5FcltbNF1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy40CgojIGNsdXN0ZXIgNAoKTjEuYzQgPC0gQ2x1c3Rlck1hcmtlcnMgJT4lIGZpbHRlcihjbHVzdGVyID09IDQgJiBhdmdfbG9nMkZDID4gMCkKZ2VuZXMgPC0gTjEuYzQkZ2VuZQoKTjEuYzQuRXIgPC0gZW5yaWNocihnZW5lcywgZGF0YWJhc2VzID0gZGIpCnBsb3RFbnJpY2goTjEuYzQuRXJbWzFdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCnBsb3RFbnJpY2goTjEuYzQuRXJbWzJdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCnBsb3RFbnJpY2goTjEuYzQuRXJbWzNdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCnBsb3RFbnJpY2goTjEuYzQuRXJbWzRdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCgpOMS5Fci5nZW5lcy4xIDwtIE4xLmM0LkVyW1sxXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjEKCk4xLkVyLmdlbmVzLjIgPC0gTjEuYzQuRXJbWzJdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMgoKTjEuRXIuZ2VuZXMuMyA8LSBOMS5jNC5FcltbM11dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4zCgpOMS5Fci5nZW5lcy40IDwtIE4xLmM0LkVyW1s0XV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjQKCiMgY2x1c3RlciA1CgpOMS5jNSA8LSBDbHVzdGVyTWFya2VycyAlPiUgZmlsdGVyKGNsdXN0ZXIgPT0gNSAmIGF2Z19sb2cyRkMgPiAwKQpnZW5lcyA8LSBOMS5jNSRnZW5lCgpOMS5jNS5FciA8LSBlbnJpY2hyKGdlbmVzLCBkYXRhYmFzZXMgPSBkYikKcGxvdEVucmljaChOMS5jNS5FcltbMV1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKcGxvdEVucmljaChOMS5jNS5FcltbMl1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKcGxvdEVucmljaChOMS5jNS5FcltbM11dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKcGxvdEVucmljaChOMS5jNS5FcltbNF1dLCBzaG93VGVybXMgPSAyMCwgbnVtQ2hhciA9IDQwLCB5ID0gIkNvdW50Iiwgb3JkZXJCeSA9ICJQLnZhbHVlIikKCk4xLkVyLmdlbmVzLjEgPC0gTjEuYzUuRXJbWzFdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMQoKTjEuRXIuZ2VuZXMuMiA8LSBOMS5jNS5FcltbMl1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4yCgpOMS5Fci5nZW5lcy4zIDwtIE4xLmM1LkVyW1szXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjMKCk4xLkVyLmdlbmVzLjQgPC0gTjEuYzUuRXJbWzRdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuNAoKIyBjbHVzdGVyIDYKCk4xLmM2IDwtIENsdXN0ZXJNYXJrZXJzICU+JSBmaWx0ZXIoY2x1c3RlciA9PSA2ICYgYXZnX2xvZzJGQyA+IDApCmdlbmVzIDwtIE4xLmM2JGdlbmUKCk4xLmM2LkVyIDwtIGVucmljaHIoZ2VuZXMsIGRhdGFiYXNlcyA9IGRiKQpwbG90RW5yaWNoKE4xLmM2LkVyW1sxXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmM2LkVyW1syXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmM2LkVyW1szXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmM2LkVyW1s0XV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQoKTjEuRXIuZ2VuZXMuMSA8LSBOMS5jNi5FcltbMV1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4xCgpOMS5Fci5nZW5lcy4yIDwtIE4xLmM2LkVyW1syXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjIKCk4xLkVyLmdlbmVzLjMgPC0gTjEuYzYuRXJbWzNdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMwoKTjEuRXIuZ2VuZXMuNCA8LSBOMS5jNi5FcltbNF1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy40CgoKIyBvdGhlciBjbHVzdGVycyAtIGNoYW5nZSB0aGUgY2x1c3RlciBudW1iZXIKTjEuYzYgPC0gQ2x1c3Rlck1hcmtlcnMgJT4lIGZpbHRlcihjbHVzdGVyID09IDExICYgYXZnX2xvZzJGQyA+IDApCmdlbmVzIDwtIE4xLmM2JGdlbmUKCk4xLmM2LkVyIDwtIGVucmljaHIoZ2VuZXMsIGRhdGFiYXNlcyA9IGRiKQpwbG90RW5yaWNoKE4xLmM2LkVyW1sxXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmM2LkVyW1syXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmM2LkVyW1szXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmM2LkVyW1s0XV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQoKTjEuRXIuZ2VuZXMuMSA8LSBOMS5jNi5FcltbMV1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4xCgpOMS5Fci5nZW5lcy4yIDwtIE4xLmM2LkVyW1syXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjIKCk4xLkVyLmdlbmVzLjMgPC0gTjEuYzYuRXJbWzNdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMwoKTjEuRXIuZ2VuZXMuNCA8LSBOMS5jNi5FcltbNF1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy40CgoKYGBgCgpjbHVzdGVyIDAgLSBhc3Ryb2N5dGUsIHJhZGlhbCBnbGlhLCBtaWNyb2dsaWEsIHN0cmlhdHVtIC0gdmVyeSBmZXcgZ2VuZXMgaW4gdGhlc2UgdGVybXMKY2x1c3RlciAxIC0gYWRyZW5hbCwgdGhhbG11cywgZW5kb3RoZWxpYWwsIGFzdHJvY3l0ZXMsIG5ldXJvbnMKY2x1c3RlcnMgMiAtIG5ldXJhbCBwbGF0ZSwgc3RyYXR1bSwgbmV1cm9ucywgTlBDLCBzdGVtLCBhc3RybyxuZXVyb2VuZG9jcmluZQpjbHVzdGVyIDMgLSBicmFpbiBtb2xlY3VsYXIgbGF5ZXIsIGVuZG90aGVsaWFsLCBhc3Ryb2N5dGUgZW1icnlvbmljLCAKY2x1c3RlciA0IC0gREcsIHN0cmlhdHVtIENBMywgR0FCQWVyZ2ljIG5ldXJvbnMKY2x1c3RlciA1IC0gREcsIG5ldXJvbnMsIEdsdXRhbWF0ZXJnaWMgbmV1cm9ucwpjbHVzdGVyIDYgLSBuZXVyb25zLCBhc3Ryb2N5dGUsIG1pY3JvZ2xpYSwgR0FCQW5ldXJvbnMKY2x1c3RlciA3IC0gbmV1cm9ucywgZ2x1dCBhbmQgZ2FiYQpjbHVzdGVyIDggLSBhc3Ryb2N5dGUsIGVuZG90aGVsaWFsLCBwZXJpY3l0ZQpjbHVzdGVyIDkgLSBlcGl0aGVsaWFsLCBlbWJyeW9uaWMgYXN0cm9jeXRlcywgR0FCQSBuZXVyb25zCmNsdXN0ZXIgMTAgLSBlcGl0aGVsaWFsCmNsdXN0ZXIgMTEgLSBlbmRvdGhlbGlhbCwgaW1tdW5lIGNlbGxzIFQgY2VsbHMKCgpFeHByZXNzaW9uIG9mIG1hcmtlcnMgZ2VuZXMgaW4gTmV1cm9uczIgCgpgYGB7cn0KCmZlYXR1cmVfbGlzdCA9IGMoIk1LSTY3IiwiU09YMiIsIlBPVTVGMSIsIkRMWDIiLCJQQVg2IiwiU09YOSIsIkhFUzEiLCJORVMiLCJSQkZPWDMiLCJNQVAyIiwiTkNBTTEiLCJDRDI0IiwiR1JJQTIiLCJHUklOMkIiLCJHQUJCUjEiLCJHQUQxIiwiR0FEMiIsIkdBQlJBMSIsIkdBQlJCMiIsIlRIIiwiQUxESDFBMSIsIkxNWDFCIiwiTlI0QTIiLCJDT1JJTiIsIkNBTEIxIiwiS0NOSjYiLCJDWENSNCIsIklUR0E2IiwiU0xDMUEzIiwiQ0Q0NCIsIkFRUDQiLCJTMTAwQiIsICJQREdGUkEiLCJPTElHMiIsIk1CUCIsIkNMRE4xMSIsIlZJTSIsIlZDQU0xIikKCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBmZWF0dXJlX2xpc3QsIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMiwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC42JykKRG90UGxvdChzZXUucSwgZmVhdHVyZXMgPSBmZWF0dXJlX2xpc3QpICtSb3RhdGVkQXhpcygpCgpQRF9wb3VsaW4gPSBjKCJUSCIsIlNMQzZBMyIsIlNMQzE4QTIiLCJTT1g2IiwiTkRORiIsIlNOQ0ciLCJBTERIMUExIiwiQ0FMQjEiLCJUQUNSMiIsIlNMQzE3QTYiLCJTTEMzMkExIiwiT1RYMiIsIkdSUCIsIkxQTCIsIkNDSyIsIlZJUCIpCgpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gUERfcG91bGluLCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIsIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjAuNicpCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gUERfcG91bGluKStSb3RhdGVkQXhpcygpCgplYWxyeU5ldXIgPSBjKCJEQ1giLCJORVVST0QxIiwiVEJSMSIpCnByb2xpZmVyYXRpb24gPSBjKCJQQ05BIiwiTUtJNjciKQpuZXVyYWxzdGVtID0gYygiU09YMiIsIk5FUyIsIlBBWDYiLCJNQVNIMSIpCgpmZWF0dXJlX2xpc3QgPC0gYygiRENYIiwiTkVVUk9EMSIsIlRCUjEiLCJQQ05BIiwiTUtJNjciLCJTT1gyIiwiTkVTIiwiUEFYNiIsIk1BU0gxIikKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IGZlYXR1cmVfbGlzdCwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjYnKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IGZlYXR1cmVfbGlzdCkrUm90YXRlZEF4aXMoKQojIG5vIHByb2xpZmVyYXRpb24gbWFya2VyIGV4cHJlc3Npb24gIFBDTkEgb3IgTUtJNjcKIyBjbHVzdGVyIDQgREEgbmV1cm9ucyAtIHNob3dzIGVhcmx5IG5ldXJvbiBtYXJrZXIgYW5kIGxvdyBQQVggNAojIGNsdXN0ZXIgMyBoYXMgaGlnaGVyIFNPWDIgLSBuZXVyb2JsYXN0IG1hcmtlciAvIE5QQyBtYXJrZXIKCm1hdF9uZXVyb24gPSBjKCJSQkZPWDMiLCJTWVAiLCJETEc0NSIsIlZBTVAxIiwiVkFNUDIiLCJUVUJCMyIsIlNZVDEiLCJCU04iLCJIT01FUjEiLCJTTEMxN0E2IikgCiMgTmV1TiBpcyBGT1gzIC0gUkJGT1gzCiMgUFNEOTUgYWxzbyBTUC05MCBvciBETEc0CiMgVkdMVVQyIGlzIFNMQzE3QTYKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IG1hdF9uZXVyb24sIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMiwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC42JykKIyBjbHVzdGVyIDQgYWxzbyBzaG93IG1hdHVyZSBuZXVyb24gbWFya2VycwpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IG1hdF9uZXVyb24pK1JvdGF0ZWRBeGlzKCkKIyBleGNpdGF0b3J5IG5ldXJvbiBtYXJrZXJzCmV4ID0gYygiR1JJQTIiLCJHUklBMSIsIkdSSUE0IiwiR1JJTjEiLCJHUklOMkIiLCJHUklOMkEiLCJHUklOM0EiLCJHUklOMyIsIkdSSVAxIiwiQ0FNSzJBIikKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IGV4LCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIsIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjAuNicpCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gZXgpK1JvdGF0ZWRBeGlzKCkKIyBpbmhpYml0b3J5IG5ldXJvbiBtYXJrZXJzCmluaCA9IGMoIkdBRDEiLCJHQUQyIiwgIkdBVDEiLCJQVkFMQiIsIkdBQlIyIiwiR0FCUjEiLCJHQlJSMSIsIkdBQlJCMiIsIkdBQlJCMSIsIkdBQlJCMyIsIkdBQlJBNiIsIkdBQlJBMSIsIkdBQlJBNCIsIlRSQUsyIikKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IGluaCwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjYnKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IGluaCkrUm90YXRlZEF4aXMoKQojIGNsdXN0ZXIgNCBpcyBtb3JlIGV4Y2l0YXRvcnkgdGhhbiBpbmhiaXRvcnkgYnV0IG5laXRoZXIgbWFya2VyIHNldCBoYXMgbXVjaCBleHByZXNzaW9uIAoKIyMjIGdsaWEgbWFya2VycwptaWNyb2dsaWEgPSBjKCJQVFBSQyIsIkFJRjEiLCJBREdSRTEiKSAgIyBBREdSRTEgaXMgYSBtaWNyb2dsaWEgbWFya2VyIEY0LzgwLCBDRDQ1IGlzIFBUUFJDLCBnZW5lIG5hbWUgSUJBMSBpcyBBSUYxCmFzdG9sZ05QQ3Byb21pY3JvID0gYygiR0ZBUCIsIlMxMDBCIiwiU0xDMUEyIiwiTUJQIiwiU09YMTAiLCJTUFAxIiwiRENYIiwiTkVVUk9EMSIsIlRCUjEiLCJQQ05BIiwiTUtJNjciLCJQVFBSQyIsIkFJRjEiLCJBREdSRTEiKQojIG5vdGUgR0xUMSBpcyBFQUFUMiB3aGljaCBpcyBTTEMxQTIgZ2x1dGF0bWF0ZSB0cmFuc3BvcnRlcgojIGVwaXRoZWxpYWwKZXBpID0gYygiSEVTMSIsIkhFUzUiLCJTT1gyIiwiU09YMTAiLCJORVMiLCJDREgxIiwiTk9UQ0gxIikgIyBlLWNhZGhlcmluIGlzIENESDEKCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBhc3RvbGdOUENwcm9taWNybywgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjYnKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IGFzdG9sZ05QQ3Byb21pY3JvLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjYnKStSb3RhdGVkQXhpcygpCiMgY2x1c3RlciA0IGlzIG1vcmUgZXhjaXRhdG9yeSB0aGFuIGluaGJpdG9yeSBidXQgbmVpdGhlciBtYXJrZXIgc2V0IGhhcyBtdWNoIGV4cHJlc3Npb24gCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBlcGksIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMiwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC42JykKRG90UGxvdChzZXUucSwgZmVhdHVyZXMgPSBlcGksIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjAuNicpK1JvdGF0ZWRBeGlzKCkKCiMgYWxzbyBhZGQgUmFkaWFsIGdsaWEgbWFya2VyIG92ZXJsYXAgd2l0aCBHbGlhIGFuZCBOZXVyb25zCgpmZWF0dXJlcyA8LSBjKCJQVFBSQyIsIkFJRjEiLCJBREdSRTEiLCAiVklNIiwgIlROQyIsIlBUUFJaMSIsIkZBTTEwN0EiLCJIT1BYIiwiTElGUiIsCiAgICAgICAgICAgICAgIklUR0I1IiwiSUw2U1QiKQpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gZmVhdHVyZXMsIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMiwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC42JykKRG90UGxvdChzZXUucSwgZmVhdHVyZXMgPSBmZWF0dXJlcywgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC42JykrUm90YXRlZEF4aXMoKQoKCmBgYAoKCkxhYmVsIHRoZSBOZXVyb24yIEZBQ1MgcG9wdWxhdGlvbiAKCmBgYHtyfQoKSWRlbnRzKHNldS5xKSA8LSAnUk5BX3Nubl9yZXMuMC42JwpjbHVzdGVyLmlkcyA8LSBjKCJOZXVyb25zMSIsImltbWF0dXJlTmV1cm9uczEiLCJOZXVyb25zMiIsCiAgICAgICAgICAgICAgICAgIk90aGVyIiwiREFuZXVyb25zMSIsIkRBbmV1cm9uczIiLCJpbW1hdHVyZU5ldXJvbnMyIiwKICAgICAgICAgICAgICAgICAiREFuZXVyb25zMyIsIlJHIiwiaW1tYXR1cmVOZXVyb25zMSIsIkVwaXRoZWxpYWwiLCJFbmRvdGhlbGlhbCIpCnVuaXF1ZShzZXUucSRSTkFfc25uX3Jlcy4wLjYpCgpuYW1lcyhjbHVzdGVyLmlkcykgPC0gbGV2ZWxzKHNldS5xKQpzZXUucSA8LSBSZW5hbWVJZGVudHMoc2V1LnEsIGNsdXN0ZXIuaWRzKQpzZXUucSRzdWJncm91cHMgPC0gSWRlbnRzKHNldS5xKQoKRGltUGxvdChzZXUucSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIGdyb3VwLmJ5ID0gJ3N1Ymdyb3VwcycsIHJlcGVsID0gVFJVRSkKCgojIGxhYmVsIGFnYWluIHdpdGgganVzdCBudW1iZXJpbmcKIyB0aGVuIEknbGwgZmluZCBtYXJrZXJzIGluIHBhaXJzIHRvIGRpc3Rpbmd1aXNoIGdyb3Vwcy4gCgpJZGVudHMoc2V1LnEpIDwtICdSTkFfc25uX3Jlcy4wLjYnCmNsdXN0ZXIuaWRzIDwtIGMoIk5ldXJvbnMxIiwiTmV1cm9uczIiLCJOZXVyb25zMyIsCiAgICAgICAgICAgICAgICAgIk90aGVyIiwiREFuZXVyb25zMSIsIkRBbmV1cm9uczIiLCJOZXVyb25zNCIsCiAgICAgICAgICAgICAgICAgIkRBbmV1cm9uczMiLCJSRyIsIk5ldXJvbnMyIiwiRXBpdGhlbGlhbCIsIkVuZG90aGVsaWFsIikKdW5pcXVlKHNldS5xJFJOQV9zbm5fcmVzLjAuNikKCm5hbWVzKGNsdXN0ZXIuaWRzKSA8LSBsZXZlbHMoc2V1LnEpCnNldS5xIDwtIFJlbmFtZUlkZW50cyhzZXUucSwgY2x1c3Rlci5pZHMpCnNldS5xJG51bWJlci5ncm91cHMgPC0gSWRlbnRzKHNldS5xKQoKRGltUGxvdChzZXUucSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIGdyb3VwLmJ5ID0gJ251bWJlci5ncm91cHMnLCByZXBlbCA9IFRSVUUpCgoKc2F2ZVJEUyhzZXUucSwgIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BoZW5vSUQvc2NSTkFzZXFTb3J0ZWQvb2Jqcy9OZXVyb25zMkxhYmVsc1NldTMwMDkyMDIyLlJEUyIpCgoKCmBgYAoKCgpGaW5kIG1hcmtlcnMgaW4gcGFpcnMgdG8gZ28gYmFjayBhbmQgY2xhc3NpZnkgdGhlIHN1Ymdyb3Vwcy4KV2lsbCBuZWVkIHRvIHJldHVybiB0byB0aGlzIGZvciBOZXVyb25zMSBGQUNTCgpOZXVyb25zIDUgYW5kIE5ldXJvbnMyIGhhZCBzaW1pbGFyIG1hcmtlcnMgYW5kIHdlcmUgbWVyZ2VkClN1YnNldCBhZ2FpbgoKYGBge3J9CgojIGZhc3RlciB0byBtYWtlIGEgc3Vic2V0IG9iamVjdHMgb2Ygb25seSBuZXVyb25zIGFuZCB1c2UgZmluZCBhbGwgbWFya2VycwoKbmV1cm9uLnN1YiA8LSBzdWJzZXQoc2V1LnEsIGlkZW50cyA9IGMoIk5ldXJvbnMxIiwiTmV1cm9uczIiLCJOZXVyb25zMyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOZXVyb25zNCIpKQoKbmV1cm9uLnN1Yi5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKG5ldXJvbi5zdWIpCgp0b3A1IDwtIG5ldXJvbi5zdWIubWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKG49NSwgd3QgPSBhdmdfbG9nMkZDKQpEb0hlYXRtYXAobmV1cm9uLnN1YiwgZmVhdHVyZXMgPSB0b3A1JGdlbmUsIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMikKCkRvdFBsb3QobmV1cm9uLnN1YiwgZmVhdHVyZXMgPSB0b3A1JGdlbmUpICsgUm90YXRlZEF4aXMoKQoKCiMgbmV1cm9ucyA1IHdhcyBqb2luZWQgdG8gTmV1cm9ucyAyCiMgY2x1c3RlciBtYXJrZXJzIGRvbmUgYWdhaW4KCiMgTmV1cm9uczEgOiBNR1AgKHRhcmdldGluZyBuZXVyYWwgcHJvamVjdGlvbnMgQk1QIHNpZ25hbGluZyksIEhQRCAoZXhjaXRhdG9yeSBhbmQgaW5pYml0b3J5LCBjb3VsZCBiZSBjZWxsIGFkaGVzaW9uIG9yIGFwb3B0b3NpcyksIE1TWDEgKHRyYW5zY3JpcHRpb24gZmFjdG9yIEJNUCBzaWduYWxpbmcsIG1pZGJyYWluIG1hcmtlciwgZGV2ZWxvcG1lbnRhbCksIENZUDFCMSAocmVkb3ggaG9tZW9zdGF0aXMpICAgCiMgTUdQLCBIUEQsIE1TWDEsIENZUDFCMQoKIyB0aGVyZSBpc24ndCBhIGdvb2QgcHJvcG9ydGlvbiBvZiBjZWxscyBleHByZXNzaW9uIGFueSBvZiB0aGUgbWFya2VycywgTmV1cm9uczIgaGFzIHRoZSBiZXN0IGFtb3VudAoKIyBOZXVyb25zMjogVEZQMTIgc2VyaW5lIHByb3RlYXNlIG1lbGF0b25pbiBjb252ZXJzaW9uLCBQVE4gKGN5dG9raW5lIHNpZ25hbGluZyksIExZZ0ggKGluaGFuY2VzIG5BQ2hScyksIFMxMDBBMTAgKG1vZHVsYXRlcyBzZXJvdG9uaW4gcmVjZXB0b3IpLCBJRkkyNyAoYW50aXZpcmFsIGFjdGl2aXR5KQojVEZQMTIsUFROLCBMWTZILCBTMTAwQTEwLCBJRkkyNyAKCiMgTmV1cm9uczM6IFNPWDQsIEFTQ0wxIChuZXVyb2dlbmVzaXMpLAoKIyBTT1g0IGlzIGEgbWFya2VyIG9mIDMgYnV0IGhhcyBoaWdoIGV4cHJlc3Npb24gaW4gNCBhcyB3ZWxsIAoKIyBOZXVyb25zNDogUENBVDQgKG5vdCBub3RlZCBpbiBuZXVyb25zKSwgVFBIMSAoNUhUIHN5bnRoZXNpcyksIEdLNSAobmV1cm9uYWwgbWFpbnRhaW5hbmNlKSwgU1NUIChzb21hdG9zdGF0aW4sIEdBQkEgc3Bpa2UgcmVndWxhdGlvbiksIFRUUiAobmV1cmFsIHByb3RlY3RpdmUgaW4gQUQpCiMgUENBVDQsIFRQSDEsIEdLNSwgU1NULCBUVFIKCiMgbWFya2VycyB0byB1c2UKCiMgTmV1cm9uczE6IE1TWDEsIENZUDFCMSAgICAgIAojIE5ldXJvbnMyOiBMWTZILCBTMTAwQTEwICAgICAKIyBOZXVyb25zMzogU09YNCwgQVNDTDEgKE5ldXJvZ2VuZXNpcykgSW1tYXR1cmUKIyBOZXVyb25zNDogR0s1LCBTU1QgICAgICAgICAgICAgICAgICAgICAgICAgTW9yZSBtYXR1cmUKCgoKIyBNYXliZSBuZXVyb25zIDEgYW5kIDIgY291bGQgYmUgbWVyZ2VkCgojIGxldHMgc2VlIGhvdyB0aGUgbWFya2VycyB3b3VsZCBsb29rCgpuZXVyb25zLjFhbmQyIDwtIEZpbmRNYXJrZXJzKG5ldXJvbi5zdWIsIGlkZW50LjEgPSBjKCJOZXVyb25zMSIsIk5ldXJvbnMyIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWRlbnQuMiA9IGMoIk5ldXJvbnMzIiwiTmV1cm9uczQiKSkKCnRvcDEwIDwtIG5ldXJvbnMuMWFuZDIgJT4lIHRvcF9uKG49MTAsIHd0ID0gYXZnX2xvZzJGQykKZnQudXAgPC0gcm93bmFtZXModG9wMTApICMgdXAgaW4gTmV1cm9uczEgYW5kIDMKdG9wMTAgPC0gbmV1cm9ucy4xYW5kMiAlPiUgdG9wX24obj0tMTAsIHd0ID0gYXZnX2xvZzJGQykKZnQuZG93biA8LSByb3duYW1lcyh0b3AxMCkKZmVhdHVyZXMgPC0gYyhmdC51cCxmdC5kb3duKQoKRG9IZWF0bWFwKG5ldXJvbi5zdWIsIGZlYXR1cmVzID0gZmVhdHVyZXMsIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMikKCkRvdFBsb3QobmV1cm9uLnN1YiwgZmVhdHVyZXMgPSBmZWF0dXJlcykgKyBSb3RhdGVkQXhpcygpCgojIGFsbCB0aGUgbWFya2VycyB3ZXJlIHVwIHJlZ3VsYXRlZCBpbiBuZXVyb25zMiBhbmQgbm90IHJlYWxseSBuZXVyb25zMQojIEknbGwga2VlcCB0aGVtIHNlcGFyYXRlZAoKCmBgYAoKClVzZSBzdWJncm91cGluZyBhbmQgZmluZCBjbHVzdGVyIG1hcmtlcnMgdG8gbG9vayBhdCBuZXVyb25hbCBzdWJ0eXBlcy4KCmBgYHtyfQoKIyBmYXN0ZXIgdG8gbWFrZSBhIHN1YnNldCBvYmplY3RzIG9mIG9ubHkgbmV1cm9ucyBhbmQgdXNlIGZpbmQgYWxsIG1hcmtlcnMKCm5ldXJvbi5zdWIgPC0gc3Vic2V0KHNldS5xLCBpZGVudHMgPSBjKCJEQW5ldXJvbnMxIiwiREFuZXVyb25zMiIsIkRBbmV1cm9uczMiKSkKCm5ldXJvbi5zdWIubWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhuZXVyb24uc3ViKQoKdG9wNSA8LSBuZXVyb24uc3ViLm1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuPTUsIHd0ID0gYXZnX2xvZzJGQykKRG9IZWF0bWFwKG5ldXJvbi5zdWIsIGZlYXR1cmVzID0gdG9wNSRnZW5lLCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIpCgpEb3RQbG90KG5ldXJvbi5zdWIsIGZlYXR1cmVzID0gdG9wNSRnZW5lKSArIFJvdGF0ZWRBeGlzKCkKCiMgbWFya2VycyBhcmUgbXVjaCBjbGVhcmVyIGZvciB0aGUgREEgbmV1cm9uIHN1Ymdyb3VwcwoKIyBEQSBuZXVyb25zIDE6IFdJRjEsIENZUDFCMSwgSUdGQlAzLCBIUEQsIFdGSUtLTjIKIyBXSUYxIChzZWNyZXRlZCBXTlQgaW5oaWJpdG9yLCBwcm9tb3RlcyByZWdlbmVyYXRpb24pLCBDWVAxQjEgKHJlZG94IGhvbWVvc3RhdGlzKSwgSUdGQlAzIChwcm9sYWN0aW4gc2VjcmV0aW9uIHJlZ3VsYXRpb24gaHlwb3RoYWxtdXMpLCBIUEQgKG5ldXJvIHByb3RlY3RpdmUpLCBXRklLS04yIChSZWNlcHRvciBmb3IgVE5DKQojIERBIG5ldXJvbnMyOiBDREg3LCBSVU5YMVQxLCBBU0NMMSwgRExLMSwgTUVHMwojIENESDcgKG5ldXJvIGNpcmN1aXRyeSBkZXZlbG9wbWVudCwgU0VNQSksIFJVTlgxVDEgKG5ldXJvbmFsIGRpZmZlcmVudGlhdGlvbiksIEFTQ0wxIChuZXVyb25hbCBkaWZmZXJlbnRpYXRpb24pLCBETEsxIChuZXVyYWwgZGlmZmVyZW50YXRpb24pLCBNRUczIChuZXVyYWwgaG9tZW9zdGF0aXMpICAKIyBEQSBuZXVyb25zMzogUENBVDQsIE5FVVJPRDEsIE5DS0FQNSwgR0s1LCBTU1QKIyBQQ0FUNCAoZGVuZHJpdGljIGdyb3d0aCksIE5FVVJPRDEgKG5ldXJhbCBkaWZmZXJlbnRhdGlvbiksIE5DS0FQNSAoRXhjaXRvcnkgbmV1cm9ucyksIEdLNSAoVEggKSwgU1NUIChyZWd1YWxhdGVzIHNwaWtlIHRpbWVzKQoKIyBEQSBuZXVyb25zMTogQ1lQMUIxLCBJR0ZCUDMKIyBEQSBuZXVyb25zMjogUlVOWDFUMSwgQVNDTDEKIyBEQSBuZXVyb25zMzogTkVVUk9EMSwgTkNLQVA1CgoKYGBgCgoKTmFtZSB0aGUgTmV1cm9uczIgRkFDUyBwb3B1bGF0aW9uIHdpdGggdGhlIE5ldXJvbiBzdWJ0eXBlIGxhdHRlci4KCmBgYHtyfQoKSWRlbnRzKHNldS5xKSA8LSAnUk5BX3Nubl9yZXMuMC42JwpjbHVzdGVyLmlkcyA8LSBjKCJOZXVyb25zLU1TWDEiLCJOZXVyb25zLUxZNkgiLCJOZXVyb25zLUFTQ0wxIiwKICAgICAgICAgICAgICAgICAiT3RoZXIiLCJEQW5ldXJvbnMtQ1lQMUIxIiwiREFuZXVyb25zLUFTQ0wxIiwiTmV1cm9ucy1HSzUiLAogICAgICAgICAgICAgICAgICJEQW5ldXJvbnMtTkVVUk9EMSIsIlJHIiwiTmV1cm9ucy1MWTZIIiwiRXBpdGhlbGlhbCIsIkVuZG90aGVsaWFsIikKCnVuaXF1ZShzZXUucSRSTkFfc25uX3Jlcy4wLjYpCgpuYW1lcyhjbHVzdGVyLmlkcykgPC0gbGV2ZWxzKHNldS5xKQpzZXUucSA8LSBSZW5hbWVJZGVudHMoc2V1LnEsIGNsdXN0ZXIuaWRzKQpzZXUucSRjZWxsc3ViZ3JvdXBzIDwtIElkZW50cyhzZXUucSkKCkRpbVBsb3Qoc2V1LnEsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCBncm91cC5ieSA9ICdjZWxsc3ViZ3JvdXBzJywgcmVwZWwgPSBUUlVFKQoKCmBgYAoKCglwcmVkdWN0aW9uIHN1bW1hcnkJQ2VsbF9UeXBlcwowCW5ldXJvbnMJTmV1cm9ucwoxCU5QQy9vbGlnby9hc3Ryby9uZXVyb25zL1JHCU5ldXJvbnMKMgluZXVyb25zCU5ldXJvbnMKMwlOUEMvUkcvQXN0cm8JTmV1cm9ucwo0CVJHL2VuZG8JUkcKNQlEQSBuZXVyb25zCU5ldXJvbnMKNglOZXVyb25zCU5ldXJvbnMKNwlEQSBuZXVyb25zCU5ldXJvbnMKOAlSRy9lbmRvCUVuZG90aGVsaWFsCjkJUkcvYXN0cm8JQXN0cm8KMTAJb3BjL25wYy9hc3Ryby9uZXVyb25zCU5ldXJvbnMKMTEJbmV1cm9ucy9kaXZpZGluZy9SRwlOZXVyb25zCgpDbHVzdGVyaW5nIGhpZ2hlciByZXMKcmVzIDEuMgkKMAlOZXVyb25zCjEJTmV1cm9ucwoyCU5ldXJvbnMKMwlBc3Ryby9SRy9OZXVyb25zCjQJUkcvQXN0cm8vTmV1cm9ucwo1CVJHL05ldXJvbnMvTlBDCjYJUkcvTlBDL0VuZG8KNwlOZXVyb25zIERBCjgJTmV1cm9ucwo5CU5ldXJvbnMgREEKMTAJTmV1cm9ucyBEQQoxMQlSRy9FbmRvCjEyCVJHL0FzdHJvIAoxMwlSRy9Bc3Ryby9OZXVyb25zCjE0CU5ldXJvbnMvUkcKCgoKCmBgYHtyfQoKSWRlbnRzKHNldS5xKSA8LSAnUk5BX3Nubl9yZXMuMS4yJwojIGhpZ2hsaWdodCB0aGUgREEgbmV1cm9ucwpjbHVzdGVyLmlkcyA8LSBjKCJOZXVyb25zIiwiTmV1cm9ucyIsIk5QQyIsCiAgICAgICAgICAgICAgICAgIk5ldXJvbnMiLCJOZXVyb25zIiwiTmV1cm9ucyIsCiAgICAgICAgICAgICAgICAgIk5ldXJvbnMgREEiLCJOZXVyb25zIiwiTmV1cm9ucyBEQSIsCiAgICAgICAgICAgICAgICAgIk5ldXJvbnMgREEiLCAiTmV1cm9ucyBEQSIsIkVuZG90aGVsaWFsIiwKICAgICAgICAgICAgICAgICAiUkcvQXN0cm8iLCJSRy9Bc3Ryby9OZXVyb25zIiwiTmV1cm9ucy9SRyIpCmNsdXN0ZXIuaWRzIDwtIGMoIk5ldXJvbnMiLCJOZXVyb25zIiwiTmV1cm9ucyIsCiAgICAgICAgICAgICAgICAgIk5ldXJvbnMiLCJOZXVyb25zIiwiTlBDIiwKICAgICAgICAgICAgICAgICAiTmV1cm9ucyIsIk5ldXJvbnMiLCJOZXVyb25zIiwKICAgICAgICAgICAgICAgICAiTmV1cm9ucyIsICJOZXVyb25zIiwiRW5kb3RoZWxpYWwiLAogICAgICAgICAgICAgICAgICJBc3Ryb2N5dGVzIiwiUmFkaWFsIEdsaWEiLCJSYWRpYWwgR2xpYSIpCgpuYW1lcyhjbHVzdGVyLmlkcykgPC0gbGV2ZWxzKHNldS5xKQpzZXUucSA8LSBSZW5hbWVJZGVudHMoc2V1LnEsIGNsdXN0ZXIuaWRzKQpzZXUucSRDZWxsX1R5cGVzIDwtIElkZW50cyhzZXUucSkKCkRpbVBsb3Qoc2V1LnEsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCBncm91cC5ieSA9ICdDZWxsX1R5cGVzJywgcmVwZWwgPSBUUlVFKQojRGltUGxvdChzZXUucSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjEuMicsIHJlcGVsID0gVFJVRSkKCiNjbHVzdHJlZShzZXUucSkKCgpgYGAKCgpgYGB7cn0KCiMgc2F2ZSB0aGUgTmV1cm9uczIgd2l0aCBsYWJlbHMKCnNhdmVSRFMoc2V1LnEsICIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QaGVub0lEL3NjUk5Bc2VxU29ydGVkL29ianMvTmV1cm9uczJMYWJlbHNTZXUzMDA5MjAyMi5SRFMiKQoKYGBgCgoKRkFDUyBwb3B1bGF0aW9uIEdsaWExIChzaG91bGQgYmUgYXN0cm9jeXRlcykKCmBgYHtyfQojIGV4cGxvcmUgZmlsdGVyaW5nCnNldSA8LSBHbGlhMQpzZXUKIyAKVmxuUGxvdChzZXUsIHB0LnNpemUgPSAwLjEwLCBmZWF0dXJlcyA9IGMoIm5GZWF0dXJlX1JOQSIsICJuQ291bnRfUk5BIiwgInBlcmNlbnQubXQiKSwgbmNvbCA9IDMpCgpWbG5QbG90KHNldSwgcHQuc2l6ZSA9IDAuMTAsIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiksIHkubWF4ID0gMTAwMCkKVmxuUGxvdChzZXUsIHB0LnNpemUgPSAwLjEwLCBmZWF0dXJlcyA9IGMoIm5GZWF0dXJlX1JOQSIpLCB5Lm1heCA9IDUwMCkKVmxuUGxvdChzZXUsIHB0LnNpemUgPSAwLjEwLCBmZWF0dXJlcyA9IGMoIm5Db3VudF9STkEiKSwgeS5tYXggPSAyMDAwKQoKIyBmaWx0ZXIgbW9yZSBjZWxscwoKc2V1LmZ0IDwtIHN1YnNldChzZXUsIHN1YnNldCA9IG5GZWF0dXJlX1JOQSA+IDMwMCAmIG5Db3VudF9STkEgPiA1MDAgJiBuQ291bnRfUk5BIDwgMTAwMDApIApzZXUuZnQKCiMgc3RpbGwgYSBsb3Qgb2YgY2VsbHMgNDcyOTUKIyB3aWxsIGxpa2VseSByZW1vdmUgYSBsb3QgbW9yZSB3aXRoIHRoZSBkb3VibGV0IGZpbmRlcgoKCmBgYAoKYGBge3J9CgpzYXZlUkRTKHNldS5mdCwgIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BoZW5vSUQvc2NSTkFzZXFTb3J0ZWQvb2Jqcy9HbGlhMUFzdHJvU2V1MDExMDIwMjIuUkRTIikKCnNldS5mdCA8LSByZWFkUkRTKCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QaGVub0lEL3NjUk5Bc2VxU29ydGVkL29ianMvR2xpYTFBc3Ryb1NldTAxMTAyMDIyLlJEUyIpCgpzZXUuZnQgPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUGhlbm9JRC9zY1JOQXNlcVNvcnRlZC9vYmpzL0dsaWExQXN0cm9TZXUwMTEwMjAyMi5SRFMiKQoKYGBgCgpEb3VibGV0IGZpbmRlcgoKYGBge3J9CgpzdXBwcmVzc01lc3NhZ2VzKHJlcXVpcmUoRG91YmxldEZpbmRlcikpCgojIGZpbHRlcmluZyBvdXQgTUFMQVQxIGFuZCBtaXRvY2hvbmRyaWFsIGdlbmVzCgpzZXUuZnQgPC0gc2V1LmZ0WyFncmVwbCgiTUFMQVQxIiwgcm93bmFtZXMoc2V1LmZ0KSksIF0Kc2V1LmZ0IDwtIHNldS5mdFshZ3JlcGwoIl5NVC0iLCByb3duYW1lcyhzZXUuZnQpKSwgXQoKIyBsaWtlIGluIHRoZSB0dXRvcmlhbCBJJ20gZm9sbG93aW5nIE1BTEFUMSBpcyB0aGUgdG9wIG1vc3QgZXhwcmVzc2VkIGdlbmUuICBUaGUgdG9wIGdlbmVzIGFyZSBhIGxvdCBvZiBNVCBhbmQgUmlib3NvbWFsIGdlbmVzCgpzZXUuZnRbWyJwZXJjZW50LnJiIl1dIDwtIFBlcmNlbnRhZ2VGZWF0dXJlU2V0KHNldS5mdCwgcGF0dGVybiA9ICJeUlAiKQoKIyBkb3duIHNhbXBsZSB0aGVyZSBhcmUgdG9vIG1hbnkgY2VsbHMgdG8gcnVuIGRvdWJsZXQgZmluZGVyCnNldS5zdWIgPC0gc3Vic2V0KHNldS5mdCwgZG93bnNhbXBsZSA9IDIwMDAwKQoKc2V1LmQgPSBOb3JtYWxpemVEYXRhKHNldS5zdWIpCnNldS5kID0gRmluZFZhcmlhYmxlRmVhdHVyZXMoc2V1LmQsIHZlcmJvc2UgPSBGKQpzZXUuZCA9IFNjYWxlRGF0YShzZXUuZCwgdmFycy50by5yZWdyZXNzID0gYygibkZlYXR1cmVfUk5BIiwgInBlcmNlbnQubXQiKSwKICAgIHZlcmJvc2UgPSBGKQpzZXUuZCA9IFJ1blBDQShzZXUuZCwgdmVyYm9zZSA9IEYsIG5wY3MgPSAxNSkKc2V1LmQgPSBSdW5VTUFQKHNldS5kLCBkaW1zID0gMToxMCwgdmVyYm9zZSA9IEYpCgpuRXhwIDwtIHJvdW5kKG5jb2woc2V1LmQpICogMC4xNSkgICMgZXhwZWN0IG1vcmUgZG91YmxldHMgYmVjYXVzZSB0aGVyZSBpcyBhIGxvdCBtb3JlIGNlbGxzCnNldS5kIDwtIGRvdWJsZXRGaW5kZXJfdjMoc2V1LmQsIHBOID0gMC4yNSwgcEsgPSAwLjA5LCBuRXhwID0gbkV4cCwgUENzID0gMToxMCkKIyB0aGUgbWVtb3J5IGxpbWl0IGlzIHJlYWNoZWQgaGVyZSAtIEkgY291bGQgcnVuIG9uIGNvbXB1dGUgY2FuYWRhCiMgRm9yIG5vdyBJJ2xsIGRvd25zYW1wbGUKIyB0aGlzIHdvcmtzCgojIG5hbWUgb2YgdGhlIERGIHByZWRpY3Rpb24gY2FuIGNoYW5nZSwgc28gZXh0cmFjdCB0aGUgY29ycmVjdCBjb2x1bW4gbmFtZS4KREYubmFtZSA9IGNvbG5hbWVzKHNldS5kQG1ldGEuZGF0YSlbZ3JlcGwoIkRGLmNsYXNzaWZpY2F0aW9uIiwgY29sbmFtZXMoc2V1LmRAbWV0YS5kYXRhKSldCgoKY293cGxvdDo6cGxvdF9ncmlkKG5jb2wgPSAyLCBEaW1QbG90KHNldS5kLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikgKyBOb0F4ZXMoKSwKICAgIERpbVBsb3Qoc2V1LmQsIGdyb3VwLmJ5ID0gREYubmFtZSkgKyBOb0F4ZXMoKSkKClZsblBsb3Qoc2V1LmQsIGZlYXR1cmVzID0gIm5GZWF0dXJlX1JOQSIsIGdyb3VwLmJ5ID0gREYubmFtZSwgcHQuc2l6ZSA9IDAuMSkKCmBgYAoKCgoKUmVtb3ZlIHRoZSBkb3VibGV0IGNlbGxzCgpgYGB7cn0Kc2V1LmQgPC0gc2V1LmRbLCBzZXUuZEBtZXRhLmRhdGFbLCBERi5uYW1lXT09ICJTaW5nbGV0Il0KZGltKHNldS5kKQpkaW0oc2V1LnN1YikKCiMgMjAwMDAgcHJlIGZpbHRlcgojIGNyZWF0ZXMgdGhlIGV4cGVjdGVkIHBlcmNlbnRhZ2UKCmBgYAoKUmVwZWF0IHdvcmtmbG93IHdpdGggZG91YmxldCByZW1vdmVkIGRhdGEgYW5kIGZpbmQgY2x1c3RlcnMgZm9yIAoKYGBge3J9CnNldSA8LSBOb3JtYWxpemVEYXRhKHNldS5kLCBub3JtYWxpemF0aW9uLm1ldGhvZCA9ICJMb2dOb3JtYWxpemUiLCBzY2FsZS5mYWN0b3IgPSAxMDAwMCkKc2V1IDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKHNldSwgc2VsZWN0aW9uLm1ldGhvZCA9ICJ2c3QiLCBuZmVhdHVyZXMgPSAyMDAwKQpzZXUgPC0gU2NhbGVEYXRhKHNldSkKc2V1IDwtIFJ1blBDQShzZXUpCnNldSA8LSBSdW5VTUFQKHNldSwgcmVkdWN0aW9uID0gInBjYSIsIG4ubmVpZ2hib3JzID0gNDMsIGRpbXMgPSAxOjMwKQpEaW1QbG90KHNldSwgcmVkdWN0aW9uID0gInVtYXAiKQoKc2V1LnEgPC0gRmluZE5laWdoYm9ycyhzZXUsIGRpbXMgPSAxOjI1LCBrLnBhcmFtID0gNDMpCnNldS5xIDwtIEZpbmRDbHVzdGVycyhzZXUucSwgcmVzb2x1dGlvbiA9IGMoMCwwLjIsMC40LDAuNikpCnNldS5xIDwtIEZpbmRDbHVzdGVycyhzZXUucSwgcmVzb2x1dGlvbiA9IGMoMCwwLjA1LDAuMSwwLjgpKQpsaWJyYXJ5KGNsdXN0cmVlKQpjbHVzdHJlZShzZXUucSkKRGltUGxvdChzZXUucSwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjA1JykKRGltUGxvdChzZXUucSwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjEnKQpEaW1QbG90KHNldS5xLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjAuMicpCkRpbVBsb3Qoc2V1LnEsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC40JykKRGltUGxvdChzZXUucSwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjYnKQpEaW1QbG90KHNldS5xLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjAuOCcpCgoKCgpgYGAKTG9vayBhdCBzb21lIGV4cHJlc3Npb24gbWFya2VycyBpbiBhIGZlYXR1cmUgcGxvdAoKYGBge3J9CiMgZ2VuZXMgcmVwb3J0ZWQgdXAgaW4gQXN0cm9jeXRlcwpGZWF0dXJlUGxvdChzZXUucSwgZmVhdHVyZXMgPSBjKCJHRkFQIiwiUzEwMEIiLCJBUVA0IiwiU0xDMUEzIiwiR0pBMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFQT0UiLCJURUFEMSIsIkdTVEE0IiwiU09YOSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlZJTSIsIkhNRzIwQSIsIkFMREgxTDEiKSkKIyBhbG1vc3Qgbm8gR0ZBUCBleHByZXNzaW9uIGFuZCBsb3RzIG9mIFMxMDBCIGV2ZXJ5d2hlcmUKCmBgYAoKCgpQcmVkaWN0IGNlbGwgdHlwZXMKCmBgYHtyfQoKCiMgU05DQSBhbmQgY29udHJvbCBtaWRicmFpbiBvcmdhbm9pZHMgMTY1IGRheXMgaW4gY3VsdHVyZQpNQk8gPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvQVNUMjNfQnJhaW5Db21tL01CT2NsdXN0ZXJzX25hbWVzMjkwNzIwMjEucmRzIikKCiMgTWlkYnJhaW4gIEFJVzAwMiAxMjAgZGF5cyBpbiBjdWx0dXJlCkFJV01CTyA8LSByZWFkUkRTKCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9BSVd0cmlvMTIwZGF5cy9NT2ludGVncmF0ZWRDbHVzdGVySzEyM3JlczAuOC5uYW1lc19ub3YxNl8yMDIxIikKCiMgTWlkYnJhaW4gQUlXMDAyIDYwIGRheXMgaW4gY3VsdHVyZQoKQUlXNjAgPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvQUlXdHJpbzYwZGF5cy9BV0kwMDJQYXJraW5LT1BpbmtLTzYwZGF5c19sYWJlbHNfMTQwNTIwMjIucmRzIikKCgojZmlyc3QgcHJlZGljdCB3aXRoIHRoZSBNQk8gZGF0YQpJZGVudHMoTUJPKSA8LSAiY2x1c3Rlcl9sYWJlbHMiCkRlZmF1bHRBc3NheShNQk8pIDwtICJSTkEiCgojIGZpbmQgdGhlIHJlZmVyZW5jZSBhbmNob3JzCnByaW50KCJmaW5kaW5nIHJlZmVyZW5jZSBhbmNob3JzIikKYW5jaG9ycyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKHJlZmVyZW5jZSA9IE1CTyAscXVlcnkgPSBzZXUucSwgZGltcyA9IDE6MjUpCnByaW50KCJnZXR0aW5nIHByZWRpY3Rpb25zIikKcHJlZGljdGlvbnMgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IGFuY2hvcnMsIHJlZmRhdGEgPSBNQk8kY2x1c3Rlcl9sYWJlbHMpCnNldS5xIDwtIEFkZE1ldGFEYXRhKHNldS5xLCBtZXRhZGF0YSA9IHByZWRpY3Rpb25zKQpwcmludCh0YWJsZShzZXUucSRwcmVkaWN0ZWQuaWQpKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwojIGFkZCBuZXcgZGF0YXNsb3QgZm9yIE1CTyBwcmVkaWN0ZWQgSUQgdG8gbWFrZSB0aGUgbmV4dCBwcmVkaWN0aW9uCnNldS5xJE1CT0FTVDIzLnByZWQgPC0gSWRlbnRzKHNldS5xKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdNQk9BU1QyMy5wcmVkJywgbGFiZWwgPSBUUlVFKQogCiMjIGNoZWNrIHRoZSBwcm9wb3J0aW9uIG9mIGNlbGwgdHlwZXMgcHJlZGljdGVkIGluIGVhY2ggY2x1c3Rlcgp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuOCwgc2V1LnEkTUJPQVNUMjMucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCgojIHRyeSBiYXIgY2hhcnQKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKQoKIyBjbHVzdGVycyBkb24ndCBicmVhayB1cCBieSB0aGUgcHJlZGljdGVkIGNlbGwgdHlwZXMKCiMjIyMjIyMjIyMjIyBhbm90aGVyIHByZWRpY3Rpb25zIG5vdyB1c2luZyB0aGUgQUlXIG9yZ2Fub2lkcwoKSWRlbnRzKEFJV01CTykgPC0gInJlczA4bmFtZXMiCkRlZmF1bHRBc3NheShBSVdNQk8pIDwtICJSTkEiCgphbmNob3JzIDwtIEZpbmRUcmFuc2ZlckFuY2hvcnMocmVmZXJlbmNlID0gQUlXTUJPICxxdWVyeSA9IHNldS5xLCBkaW1zID0gMToyNSkKcHJpbnQoImdldHRpbmcgcHJlZGljdGlvbnMiKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IEFJV01CTyRyZXMwOG5hbWVzKQpzZXUucSA8LSBBZGRNZXRhRGF0YShzZXUucSwgbWV0YWRhdGEgPSBwcmVkaWN0aW9ucykKcHJpbnQodGFibGUoc2V1LnEkcHJlZGljdGVkLmlkKSkKCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKIyBhZGQgbmV3IGRhdGFzbG90IGZvciBNQk8gcHJlZGljdGVkIElEIHRvIG1ha2UgdGhlIG5leHQgcHJlZGljdGlvbgpzZXUucSRNQk9BSVcucHJlZCA8LSBJZGVudHMoc2V1LnEpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ01CT0FJVy5wcmVkJywgbGFiZWwgPSBUUlVFKQogCiMjIGNoZWNrIHRoZSBwcm9wb3J0aW9uIG9mIGNlbGwgdHlwZXMgcHJlZGljdGVkIGluIGVhY2ggY2x1c3Rlcgp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuOCwgc2V1LnEkTUJPQUlXLnByZWQpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQoKIyB0cnkgYmFyIGNoYXJ0CmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikKCiMgdGhlIHByZWRpY3RlZCBjZWxsIHR5cGVzIG1ha2UgbW9yZSBzZW5zZSBmcm9tIHRoZSBBSVcwMDIgb3JnYW5vaWQKIyBub3cgcHJlZGljdCB3aXRoIHRoZSBBSVcwMDIgNjAgZGF5cyBvcmdhbm9pZAoKSWRlbnRzKEFJVzYwKSA8LSAiY2x1c3Rlci5pZHMiCkRlZmF1bHRBc3NheShBSVc2MCkgPC0gIlJOQSIKCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBBSVc2MCwgcXVlcnkgPSBzZXUucSwgZGltcyA9IDE6MjUpCnByaW50KCJnZXR0aW5nIHByZWRpY3Rpb25zIikKcHJlZGljdGlvbnMgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IGFuY2hvcnMsIHJlZmRhdGEgPSBBSVc2MCRjbHVzdGVyLmlkcykgCnNldS5xIDwtIEFkZE1ldGFEYXRhKHNldS5xLCBtZXRhZGF0YSA9IHByZWRpY3Rpb25zKQpwcmludCh0YWJsZShzZXUucSRwcmVkaWN0ZWQuaWQpKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwojIGFkZCBuZXcgZGF0YXNsb3QgZm9yIE1CTyBwcmVkaWN0ZWQgSUQgdG8gbWFrZSB0aGUgbmV4dCBwcmVkaWN0aW9uCnNldS5xJEFJVzYwLnByZWQgPC0gSWRlbnRzKHNldS5xKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdBSVc2MC5wcmVkJywgbGFiZWwgPSBUUlVFKQogCiMjIGNoZWNrIHRoZSBwcm9wb3J0aW9uIG9mIGNlbGwgdHlwZXMgcHJlZGljdGVkIGluIGVhY2ggY2x1c3Rlcgp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuOCwgc2V1LnEkQUlXNjAucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCgojIHRyeSBiYXIgY2hhcnQKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKQoKIyBzYXZlIG9qYmVjdCB3aXRoIHByZWRpY2l0b25zCnNhdmVSRFMoc2V1LnEsICIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QaGVub0lEL3NjUk5Bc2VxU29ydGVkL29ianMvR2xpYTFQcmVkaWN0aW9uc1NldTAxMTAyMDIyLlJEUyIpCgoKCgpgYGAKCgpQcmVkaWN0IHdpdGggdGhlIGJyYWluIHNjUk5Bc2VxCgpgYGB7cn0KCnBhdGh3YXkgPC0gIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BoZW5vSUQvc2NSTkFzZXFTb3J0ZWQvb2Jqcy8iCnNldS5xIDwtIHJlYWRSRFMocGFzdGUocGF0aHdheSwiR2xpYTFMYWJsZWRTZXUzMDExMDIwMjIuUkRTIixzZXAgPSAiIikpCgoKIyByZWFkIGluIHRoZSByZWZlcmVuY2UgZGF0YXNldAojIGZyb20gQmhhZHVyaSBtaWRicmFpbiBhbmQgc3RyaWF0dW0Kc2V1LnIgPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUHVibGljRGF0YS9CaGFkdXJpX3dob2xlQnJhaW4vQmhhZHVyaV9taWRicmFpbl9zdHJpYXR1bS5SRFMiKQoKSWRlbnRzKHNldS5yKSA8LSAiY2VsbF9jbHVzdGVyIgoKIyBmaW5kIHRoZSByZWZlcmVuY2UgYW5jaG9ycwphbmNob3JzIDwtIEZpbmRUcmFuc2ZlckFuY2hvcnMocmVmZXJlbmNlID0gc2V1LnIsIHF1ZXJ5ID0gc2V1LnEsIGRpbXMgPSAxOjI1KQpwcmludCgiZ2V0dGluZyBwcmVkaWN0aW9ucyIpCnByZWRpY3Rpb25zIDwtIFRyYW5zZmVyRGF0YShhbmNob3JzZXQgPSBhbmNob3JzLCByZWZkYXRhID0gc2V1LnIkY2VsbF9jbHVzdGVyKQpzZXUucSA8LSBBZGRNZXRhRGF0YShzZXUucSwgbWV0YWRhdGEgPSBwcmVkaWN0aW9ucykKcHJpbnQodGFibGUoc2V1LnEkcHJlZGljdGVkLmlkKSkKCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKc2V1LnEkQmhhLm1pZC5zdHJpLnByZWQgPC0gSWRlbnRzKHNldS5xKQpwcmludCh0YWJsZShzZXUucSRCaGEubWlkLnN0cmkucHJlZCkpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ0JoYS5taWQuc3RyaS5wcmVkJykKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnc3ViZ3JvdXBzJykKCiMgZG8gdGhlIHByZWRpY3Rpb25zIGRpZmZlciB3aXRoIHRoZSBtYWluIGNlbGwgdHlwZSBncm91cHMgaW5zdGVhZCBvZiB0aGUgY2x1c3RlciBpbiB0aGUgcmVmZXJlbmNlIGRhdGE/IApJZGVudHMoc2V1LnIpIDwtICJjZWxsX3R5cGUiCgojIGZpbmQgdGhlIHJlZmVyZW5jZSBhbmNob3JzCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBzZXUuciwgcXVlcnkgPSBzZXUucSwgZGltcyA9IDE6MjUpCnByaW50KCJnZXR0aW5nIHByZWRpY3Rpb25zIikKcHJlZGljdGlvbnMgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IGFuY2hvcnMsIHJlZmRhdGEgPSBzZXUuciRjZWxsX3R5cGUpCnNldS5xIDwtIEFkZE1ldGFEYXRhKHNldS5xLCBtZXRhZGF0YSA9IHByZWRpY3Rpb25zKQpwcmludCh0YWJsZShzZXUucSRwcmVkaWN0ZWQuaWQpKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdwcmVkaWN0ZWQuaWQnKQoKYGBgCgoKCgoKYGBge3J9CgojIEFJVzAwMiAxMjAgZGF5cyBwcmVkaWN0aW9ucwp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuMiwgc2V1LnEkTUJPQUlXLnByZWQpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQUlXMTIwIDwtIGFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDIsIEZyZXEpKQpkZi50b3AuYWl3MTIwIDwtIHRvcC5wcmVkLmNlbGx0eXBlLkFJVzEyMFtvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5BSVcxMjAkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUuQUlXMTIwJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5haXcxMjApIDwtIE5VTEwKZGYudG9wLmFpdzEyMCRJIDwtIHJvdy5uYW1lcyhkZi50b3AuYWl3MTIwKQoKIyBBSVcwMDIgNjAgZGF5cyBwcmVkaWN0aW9ucwp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuMiwgc2V1LnEkQUlXNjAucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5jZWxsdHlwZS5BSVc2MCA8LWFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDIsIEZyZXEpKQpkZi50b3AuYWl3NjAgPC0gdG9wLnByZWQuY2VsbHR5cGUuQUlXNjBbb3JkZXIodG9wLnByZWQuY2VsbHR5cGUuQUlXNjAkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUuQUlXNjAkRnJlcSksXQpyb3cubmFtZXMoZGYudG9wLmFpdzYwKSA8LSBOVUxMCmRmLnRvcC5haXc2MCRJIDwtIHJvdy5uYW1lcyhkZi50b3AuYWl3NjApCgoKIyBBU1QyMyAxNjUgZGF5cyBwcmVkaWN0aW9ucwp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuMiwgc2V1LnEkTUJPQVNUMjMucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5jZWxsdHlwZS5BU1QyMyA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLkFTVDIzIDwtIHRvcC5wcmVkLmNlbGx0eXBlLkFTVDIzW29yZGVyKHRvcC5wcmVkLmNlbGx0eXBlLkFTVDIzJFZhcjEsLXRvcC5wcmVkLmNlbGx0eXBlLkFTVDIzJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5BU1QyMykgPC0gTlVMTApkZi50b3AuQVNUMjMkSSA8LSByb3cubmFtZXMoZGYudG9wLkFTVDIzKQoKIyMjIGFkZCBpbiB0aGUgcHJlZGljdGlvbiBmcm9tIGJyYWluIGRhdGEgQmhhZHVyaSBtaWRicmFpbiBhbmQgc3RyaWF0dW0KdC5sYWJsZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4wLjIsIHNldS5xJEJoYS5taWQuc3RyaS5wcmVkKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKSArIFJvdGF0ZWRBeGlzKCkgCnRvcC5wcmVkLmNlbGx0eXBlLkJoYSA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLkJoYSA8LSB0b3AucHJlZC5jZWxsdHlwZS5CaGFbb3JkZXIodG9wLnByZWQuY2VsbHR5cGUuQmhhJFZhcjEsLXRvcC5wcmVkLmNlbGx0eXBlLkJoYSRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3AuQmhhKSA8LSBOVUxMCmRmLnRvcC5CaGEkSSA8LSByb3cubmFtZXMoZGYudG9wLkJoYSkKCiMjIHRoZXNlIGFyZSBjYWxjdWxhdGVkIGJlbG93CiMjIyBhZGQgaW4gdGhlIHByZWRpY3Rpb24gZnJvbSBicmFpbiB3aG9sZSBicmFpbiBkYXRhIEJoYWR1cmkgbWlkYnJhaW4gZG93biBzYW1wbGVkCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRCaGEpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQmhhMSA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLkJoYTEgPC0gdG9wLnByZWQuY2VsbHR5cGUuQmhhMVtvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5CaGEkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUuQmhhJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5CaGExKSA8LSBOVUxMCmRmLnRvcC5CaGExJEkgPC0gcm93Lm5hbWVzKGRmLnRvcC5CaGExKQoKcHJlZC50YWJsZSA8LSBtZXJnZShkZi50b3AuQVNUMjMsIGRmLnRvcC5haXc2MCwgYnkgPSAnSScsIGFsbCA9IFRSVUUpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLmFpdzEyMCwgYnkgPSAnSScpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLkJoYSwgYnkgPSAnSScpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLkJoYTEsIGJ5ID0gJ0knKQpwcmVkLnRhYmxlCgpgYGAKVGhlc2UgcHJlZGljdGlvbnMgYXJlIG5vdCBnb29kLiAgVGhlcmUgYXJlIHNldmVyYWwgYXN0cm9jeXRlIG1hcmtlcnMgYnkgZXhwcmVzc2lvbiBsZXZlbHMuICBFdmVyeXRoaW5nIGlzIHByZWRpY3RlZCBhcyBSYWRpYWwgZ2xpYSBvciBvbGlnbyBkZW5kcm9jeXRlcwoKClRyeSB0byBwcmVkaWN0IHdpdGggdGhlIHdob2xlIGJyYWluIGFuZCBzZWUgaWYgaXQncyBkaWZmZXJlbnQKCmBgYHtyfQojIHJlYWQgaW4gdGhlIHJlZmVyZW5jZSBkYXRhc2V0CiMgZnJvbSBCaGFkdXJpIG1pZGJyYWluIGFuZCBzdHJpYXR1bQpzZXUuciA8LSByZWFkUkRTKCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QdWJsaWNEYXRhL0JoYWR1cmlfd2hvbGVCcmFpbi9CaGFkdXJpX2Rvd25zYW1wbGUuUkRTIikKCklkZW50cyhzZXUucikgPC0gImNlbGxfY2x1c3RlciIKCiMgZmluZCB0aGUgcmVmZXJlbmNlIGFuY2hvcnMKYW5jaG9ycyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKHJlZmVyZW5jZSA9IHNldS5yLCBxdWVyeSA9IHNldS5xLCBkaW1zID0gMToyNSkKcHJpbnQoImdldHRpbmcgcHJlZGljdGlvbnMiKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IHNldS5yJGNlbGxfY2x1c3RlcikKc2V1LnEgPC0gQWRkTWV0YURhdGEoc2V1LnEsIG1ldGFkYXRhID0gcHJlZGljdGlvbnMpCnByaW50KHRhYmxlKHNldS5xJHByZWRpY3RlZC5pZCkpCgpJZGVudHMoc2V1LnEpIDwtICdwcmVkaWN0ZWQuaWQnCnNldS5xJEJoYSA8LSBJZGVudHMoc2V1LnEpCnByaW50KHRhYmxlKHNldS5xJEJoYSkpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ0JoYScpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ3N1Ymdyb3VwcycpCgoKCgoKYGBgCgoKCgpUcnkgdG8gcHJlZGljdCB3aXRoIHRoZSBhc3Ryb2N5dGUgS2FtYXRoIGRhdGEKCmBgYHtyfQoKYXN0cm8ucmVmIDwtIHJlYWRSRFMoIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL01hY29za29fRGF0YS9QRF9hc3Ryby5SZHMiKQojIG5lZWQgdG8gbWFrZSBQQ0EgYW5kIFVNQVAKYXN0cm8ucmVmIDwtIE5vcm1hbGl6ZURhdGEoYXN0cm8ucmVmKQphc3Ryby5yZWYgPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMoYXN0cm8ucmVmLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCmFzdHJvLnJlZiA8LSBTY2FsZURhdGEoYXN0cm8ucmVmKQphc3Ryby5yZWYgPC0gUnVuUENBKGFzdHJvLnJlZikKYXN0cm8ucmVmIDwtIFJ1blVNQVAoYXN0cm8ucmVmLCByZWR1Y3Rpb24gPSAicGNhIiwgbi5uZWlnaGJvcnMgPSAyMDUsIGRpbXMgPSAxOjI1KQoKY29sbmFtZXMoYXN0cm8ucmVmQG1ldGEuZGF0YSkKCgpJZGVudHMoYXN0cm8ucmVmKSA8LSAiQ2VsbF9TdWJ0eXBlIgpEZWZhdWx0QXNzYXkoYXN0cm8ucmVmKSA8LSAiUk5BIgoKIyBmaW5kIHRoZSByZWZlcmVuY2UgYW5jaG9ycwpwcmludCgiZmluZGluZyByZWZlcmVuY2UgYW5jaG9ycyIpCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBhc3Ryby5yZWYgLHF1ZXJ5ID0gc2V1LnEsIGRpbXMgPSAxOjIwKQpwcmludCgiZ2V0dGluZyBwcmVkaWN0aW9ucyIpCnByZWRpY3Rpb25zIDwtIFRyYW5zZmVyRGF0YShhbmNob3JzZXQgPSBhbmNob3JzLCByZWZkYXRhID0gYXN0cm8ucmVmJENlbGxfU3VidHlwZSwgay53ZWlnaHQgPSAxMCkKc2V1LnEgPC0gQWRkTWV0YURhdGEoc2V1LnEsIG1ldGFkYXRhID0gcHJlZGljdGlvbnMpCnByaW50KHRhYmxlKHNldS5xJHByZWRpY3RlZC5pZCkpCgpJZGVudHMoc2V1LnEpIDwtICdwcmVkaWN0ZWQuaWQnCiMgYWRkIG5ldyBkYXRhc2xvdCBmb3IgTUJPIHByZWRpY3RlZCBJRCB0byBtYWtlIHRoZSBuZXh0IHByZWRpY3Rpb24Kc2V1LnEkYXN0cm8ucHJlZCA8LSBJZGVudHMoc2V1LnEpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ2FzdHJvLnByZWQnLCBsYWJlbCA9IFRSVUUpCnRhYmxlKHNldS5xJGFzdHJvLnByZWQpCgpzZXUucSRwcmVkaWN0ZWQuaWQgPC0gaWZlbHNlKHNldS5xJHByZWRpY3Rpb24uc2NvcmUubWF4ID4gMC45NSwgc2V1LnEkcHJlZGljdGVkLmlkLCBOQSkKcHJpbnQodGFibGUoc2V1LnEkcHJlZGljdGVkLmlkKSkKCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKc2V1LnEkYXN0cm8ucHJlZC50aHJlc2ggPC0gSWRlbnRzKHNldS5xKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdhc3Ryby5wcmVkLnRocmVzaCcsIGxhYmVsID0gVFJVRSkKdGFibGUoc2V1LnEkYXN0cm8ucHJlZC50aHJlc2gpCgojIDE5OTg2IEFzdHJvX1ZJTV9UTkZTUkYxMkEgbm8gdGhyZXNob2xkICAgICAgQXN0cm9fR0xZQVRMMiAxNAojIDgzNzYgQXN0cm9fVklNX1RORlNSRjEyQSAgIHdpdGggOTUlIHRocmVzaG9sZAoKCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRhc3Ryby5wcmVkLnRocmVzaCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5hc3RybyA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLmFzdHJvIDwtIHRvcC5wcmVkLmFzdHJvW29yZGVyKHRvcC5wcmVkLmFzdHJvJFZhcjEsLXRvcC5wcmVkLmFzdHJvJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5hc3RybykgPC0gTlVMTAoKCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRhc3Ryby5wcmVkKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKSArIFJvdGF0ZWRBeGlzKCkgCnRvcC5wcmVkLmFzdHJvIDwtIGFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDIsIEZyZXEpKQpkZi50b3AuYXN0cm8gPC0gdG9wLnByZWQuYXN0cm9bb3JkZXIodG9wLnByZWQuYXN0cm8kVmFyMSwtdG9wLnByZWQuYXN0cm8kRnJlcSksXQpyb3cubmFtZXMoZGYudG9wLmFzdHJvKSA8LSBOVUxMCgoKCmBgYAoKCgpQb3NzaWJsZSBwcmVkaWN0ZWQgaW4gb3RoZXIgY2x1c3RlcnMKCmBgYHtyfQpjbHVzdHJlZShzZXUucSkKCmBgYAoKTWFrZSB0aGUgcHJlZGljdGlvbiB0YWJsZSBmb3IgaGlnaCByZXNvbHV0aW9uIFJlcyAwLjggMTIgY2x1c3RlcnMKCmBgYHtyfQojIEFJVzAwMiAxMjAgZGF5cyBwcmVkaWN0aW9ucwp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuOCwgc2V1LnEkTUJPQUlXLnByZWQpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQUlXMTIwIDwtIGFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDIsIEZyZXEpKQpkZi50b3AuYWl3MTIwIDwtIHRvcC5wcmVkLmNlbGx0eXBlLkFJVzEyMFtvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5BSVcxMjAkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUuQUlXMTIwJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5haXcxMjApIDwtIE5VTEwKZGYudG9wLmFpdzEyMCRJIDwtIHJvdy5uYW1lcyhkZi50b3AuYWl3MTIwKQoKIyBBSVcwMDIgNjAgZGF5cyBwcmVkaWN0aW9ucwp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuOCwgc2V1LnEkQUlXNjAucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5jZWxsdHlwZS5BSVc2MCA8LWFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDIsIEZyZXEpKQpkZi50b3AuYWl3NjAgPC0gdG9wLnByZWQuY2VsbHR5cGUuQUlXNjBbb3JkZXIodG9wLnByZWQuY2VsbHR5cGUuQUlXNjAkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUuQUlXNjAkRnJlcSksXQpyb3cubmFtZXMoZGYudG9wLmFpdzYwKSA8LSBOVUxMCmRmLnRvcC5haXc2MCRJIDwtIHJvdy5uYW1lcyhkZi50b3AuYWl3NjApCgoKIyBBU1QyMyAxNjUgZGF5cyBwcmVkaWN0aW9ucwp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuOCwgc2V1LnEkTUJPQVNUMjMucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5jZWxsdHlwZS5BU1QyMyA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLkFTVDIzIDwtIHRvcC5wcmVkLmNlbGx0eXBlLkFTVDIzW29yZGVyKHRvcC5wcmVkLmNlbGx0eXBlLkFTVDIzJFZhcjEsLXRvcC5wcmVkLmNlbGx0eXBlLkFTVDIzJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5BU1QyMykgPC0gTlVMTApkZi50b3AuQVNUMjMkSSA8LSByb3cubmFtZXMoZGYudG9wLkFTVDIzKQoKIyMjIGFkZCBpbiB0aGUgcHJlZGljdGlvbiBmcm9tIGJyYWluIGRhdGEgQmhhZHVyaSBtaWRicmFpbiBhbmQgc3RyaWF0dW0KdC5sYWJsZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4wLjgsIHNldS5xJEJoYS5taWQuc3RyaS5wcmVkKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKSArIFJvdGF0ZWRBeGlzKCkgCnRvcC5wcmVkLmNlbGx0eXBlLkJoYSA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLkJoYSA8LSB0b3AucHJlZC5jZWxsdHlwZS5CaGFbb3JkZXIodG9wLnByZWQuY2VsbHR5cGUuQmhhJFZhcjEsLXRvcC5wcmVkLmNlbGx0eXBlLkJoYSRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3AuQmhhKSA8LSBOVUxMCmRmLnRvcC5CaGEkSSA8LSByb3cubmFtZXMoZGYudG9wLkJoYSkKCiMjIHRoZXNlIGFyZSBjYWxjdWxhdGVkIGJlbG93CiMjIyBhZGQgaW4gdGhlIHByZWRpY3Rpb24gZnJvbSBicmFpbiB3aG9sZSBicmFpbiBkYXRhIEJoYWR1cmkgbWlkYnJhaW4gZG93biBzYW1wbGVkCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC44LCBzZXUucSRCaGEpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQmhhMSA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLkJoYTEgPC0gdG9wLnByZWQuY2VsbHR5cGUuQmhhMVtvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5CaGEkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUuQmhhJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5CaGExKSA8LSBOVUxMCmRmLnRvcC5CaGExJEkgPC0gcm93Lm5hbWVzKGRmLnRvcC5CaGExKQoKcHJlZC50YWJsZSA8LSBtZXJnZShkZi50b3AuQVNUMjMsIGRmLnRvcC5haXc2MCwgYnkgPSAnSScsIGFsbCA9IFRSVUUpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLmFpdzEyMCwgYnkgPSAnSScpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLkJoYSwgYnkgPSAnSScpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLkJoYTEsIGJ5ID0gJ0knKQpwcmVkLnRhYmxlCgpgYGAKCgoKCkxvb2sgYXQgY2x1c3RlciBtYXJrZXJzCgpgYGB7cn0KCklkZW50cyhzZXUucSkgPC0gJ1JOQV9zbm5fcmVzLjAuMicKQ2x1c3Rlck1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoc2V1LnEsIG9ubHkucG9zID0gVFJVRSkKCnRvcDUgPC0gQ2x1c3Rlck1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuPTUsIHd0ID0gYXZnX2xvZzJGQykKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IHRvcDUkZ2VuZSwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQoKd3JpdGUuY3N2KENsdXN0ZXJNYXJrZXJzLCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QaGVub0lEL3NjUk5Bc2VxU29ydGVkL0dsaWExQXN0cm9jeXRlc0NsdXN0ZXJNYXJrZXJzX25ldy5jc3YiKQoKIyBmb3IgdGhlIHJlcyAwLjYgdGhlIGxhcmdlcnMgZ3JvdXBzIDAgYW5kIDEgZG9uJ3QgaGF2ZSBncmVhdCBtYXJrZXJzIGFuZCBub25lIG9mIHRoZSBtYXJrZXJzIGFyZSByZWFsbHkgdmVyeSBnb29kLiAgCiMgSSdsbCByZXJ1biB3aXRoIHJlcyAwLjIKdW5pcXVlKHNldS5xJFJOQV9zbm5fcmVzLjAuMikKCiMgc3RpbGwgbm90IG11Y2ggYmV0dGVyCgoKCmBgYAoKCgpDaGVjayBjZWxsIHR5cGUgbWFya2VycyB3aXRoIEVucmljaFIKCmBgYHtyfQoKbGlicmFyeShlbnJpY2hSKQoKc2V0RW5yaWNoclNpdGUoIkVucmljaHIiKSAjIEh1bWFuIGdlbmVzCiMgbGlzdCBvZiBhbGwgdGhlIGRhdGFiYXNlcwoKIyBsaWJhcmllcyB3aXRoIGNlbGwgdHlwZXMKCmRiIDwtIGMoJ0FsbGVuX0JyYWluX0F0bGFzX3VwJywnRGVzY2FydGVzX0NlbGxfVHlwZXNfYW5kX1Rpc3N1ZV8yMDIxJywKICAgICAgICAnQ2VsbE1hcmtlcl9BdWdtZW50ZWRfMjAyMScsJ0F6aW11dGhfQ2VsbF9UeXBlc18yMDIxJykKCiMgZW5yaWNocihnZW5lcywgZGF0YWJhc2VzID0gTlVMTCkKCiNJJ2xsIHJ1biB0aGUgY2x1c3RlcnMgb25lIGF0IGEgdGltZQoKTjEuYzAgPC0gQ2x1c3Rlck1hcmtlcnMgJT4lIGZpbHRlcihjbHVzdGVyID09IDUgJiBhdmdfbG9nMkZDID4gMCkKZ2VuZXMgPC0gTjEuYzAkZ2VuZQoKTjEuYzAuRXIgPC0gZW5yaWNocihnZW5lcywgZGF0YWJhc2VzID0gZGIpCnBsb3RFbnJpY2goTjEuYzAuRXJbWzFdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCnBsb3RFbnJpY2goTjEuYzAuRXJbWzJdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCnBsb3RFbnJpY2goTjEuYzAuRXJbWzNdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCnBsb3RFbnJpY2goTjEuYzAuRXJbWzRdXSwgc2hvd1Rlcm1zID0gMjAsIG51bUNoYXIgPSA0MCwgeSA9ICJDb3VudCIsIG9yZGVyQnkgPSAiUC52YWx1ZSIpCgpOMS5Fci5nZW5lcy4xIDwtIE4xLmMwLkVyW1sxXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjEKCk4xLkVyLmdlbmVzLjIgPC0gTjEuYzAuRXJbWzJdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMgoKTjEuRXIuZ2VuZXMuMyA8LSBOMS5jMC5FcltbM11dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4zCgoKTjEuRXIuZ2VuZXMuNCA8LSBOMS5jMC5FcltbNF1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy40CgoKCiMgY2x1c3RlciAwIC0gQ2VsbCB0eXBlIG1hcmtlciBsaWJyYXJ5IC0gQnJhaW4gYXN0cm9jeXRlIHRvcCBoaXQgYW5kIGVtYnJ5b25pYyBhc3Ryb2N5dGVzCiMgZ2VuZSBsaXN0IGluIHRlcm06IGJyYWluIGFzdHJvY3l0ZQlFRkVNUDE7TkZJQTtMSVgxO1BTQVA7S0lGMjFBO1MxMDBCO0NSWUFCO0RLSzMKIyBlbWJyeW8gYXN0cm9jeXRlcwlTT1gyO0JFWDE7SE1HQ1MxO1BUUFJaMTtMSVgxO1MxMDBCO0RLSzM7SVRNMkMKCiMgY2x1c3RlciAxIC0gc3RlbSBjZWxsIHBlcmljeXRlIChicmFpbiksIHN0ZWxhdGUsIGFzdHJvY3l0ZQoKIyBjbHVzdGVyIDIgLSBoeXBvdGhhbG11cywgZW5kb3RoZWxpYWwgY2VsbHMsIG1hY3JvcGhhZ2UKIyBlbmRvdGhlbGlhbCBDU1RCO1BSRUxJRDE7TVQxWDtDUklQMjtSSE9DO1RNRU0xNDE7TVQyQTtSUFMyODtDQ0RDODVCO0VJRjNJO1JCUDE7SUQxO0M0T1JGMztJRDM7UENCRDE7TVNYMTtQUElDCgojIGNsdXN0ZXIgMyAtIHNtb290aCBtdXNjbGUgY2VsbHMKCiMgY2x1c3RlciA0IC0gTksgY2VsbHMsIGZpYnJvYmxhc3RzCiMgTksgY2VsbHMgSVRHQjE7UkFCNUM7R1NUUDE7UERDRDU7RUVGMUIyO1RHT0xOMjtTRENCUDtNVDJBO0xESEE7U05SUEQyO1lXSEFRO1pORjMyNjtUTVNCMTA7Q0NEQzUwCiMgZmlicm9ibGFzdHMgCUNPTDNBMTtDQUxEMTtDT0w2QTMKCiMgY2x1c3RlciA1IC0gZW5kb3RoZWxpYWwgY2VsbHMsIE5LIGNlbGxzLCBDRDgrCgojIGNsdXN0ZXIgNiAtIHN0cm9tYWwgY2VsbHMgZXVyeXRocm9ibGFzdHMsIG5vbmUtbmV1cm9uYWwsIG9saWdvCgojIHJlcmFuIGFuZCBub3cgdGhlcmUgYXJlIG9ubHkgNSBjbHVzdGVycwojIHJlcGVhdCBjaGVja2luZwoKCmBgYAoKQ2x1c3RlciAwIC0gYXN0cm9jeXRlcwpDbHVzdGVyIDEgLSBwZXJpY3l0ZSBhc3Ryb2N5dGUgKHdlYWsgc3RpbGwpCkNsdXN0ZXIgMiAtIGVuZG90aGVsaWFsCkNsdXN0ZXIgMyAtIHNtb290aCBtdXNjbGUKQ2x1c3RlciA0IC0gTksvZmlicm9ibGFzdApDbHVzdGVyIDUgLSBlbmRvdGhlbGlhbApDbHVzdGVyIDYgLSBub24tIG5ldXJvbmFsCgoKCgoKCgpgYGB7cn0KClZsblBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gYygiQ0Q0NCIsIklUR0IxIiwiUzEwMEIiKSwgZ3JvdXAuYnkgPSAnb3JpZy5pZGVudCcpClZsblBsb3Qoc2V1LmZ0LCBmZWF0dXJlcyA9IGMoIkNENDQiLCJJVEdCMSIsIlMxMDBCIiksIGdyb3VwLmJ5ID0gJ29yaWcuaWRlbnQnKQoKYGBgCgpDaGVjayBleHByZXNzaW9uIG9mIGtub3duIG1hcmtlcnMKCmBgYHtyfQoKSWRlbnRzKHNldS5xKSA8LSAnUk5BX3Nubl9yZXMuMC4yJwoKZmVhdHVyZV9saXN0ID0gYygiTUtJNjciLCJTT1gyIiwiUE9VNUYxIiwiRExYMiIsIlBBWDYiLCJTT1g5IiwiSEVTMSIsIk5FUyIsIlJCRk9YMyIsIk1BUDIiLCJOQ0FNMSIsIkNEMjQiLCJHUklBMiIsIkdSSU4yQiIsIkdBQkJSMSIsIkdBRDEiLCJHQUQyIiwiR0FCUkExIiwiR0FCUkIyIiwiVEgiLCJBTERIMUExIiwiTE1YMUIiLCJOUjRBMiIsIkNPUklOIiwiQ0FMQjEiLCJLQ05KNiIsIkNYQ1I0IiwiSVRHQTYiLCJTTEMxQTMiLCJDRDQ0IiwiQVFQNCIsIlMxMDBCIiwgIlBER0ZSQSIsIk9MSUcyIiwiTUJQIiwiQ0xETjExIiwiVklNIiwiVkNBTTEiKQoKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IGZlYXR1cmVfbGlzdCwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IGZlYXR1cmVfbGlzdCkgK1JvdGF0ZWRBeGlzKCkKClBEX3BvdWxpbiA9IGMoIlRIIiwiU0xDNkEzIiwiU0xDMThBMiIsIlNPWDYiLCJORE5GIiwiU05DRyIsIkFMREgxQTEiLCJDQUxCMSIsIlRBQ1IyIiwiU0xDMTdBNiIsIlNMQzMyQTEiLCJPVFgyIiwiR1JQIiwiTFBMIiwiQ0NLIiwiVklQIikKCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBQRF9wb3VsaW4sIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMikKRG90UGxvdChzZXUucSwgZmVhdHVyZXMgPSBQRF9wb3VsaW4pK1JvdGF0ZWRBeGlzKCkKCmVhbHJ5TmV1ciA9IGMoIkRDWCIsIk5FVVJPRDEiLCJUQlIxIikKcHJvbGlmZXJhdGlvbiA9IGMoIlBDTkEiLCJNS0k2NyIpCm5ldXJhbHN0ZW0gPSBjKCJTT1gyIiwiTkVTIiwiUEFYNiIsIk1BU0gxIikKCmZlYXR1cmVfbGlzdCA8LSBjKCJEQ1giLCJORVVST0QxIiwiVEJSMSIsIlBDTkEiLCJNS0k2NyIsIlNPWDIiLCJORVMiLCJQQVg2IiwiTUFTSDEiKQpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gZmVhdHVyZV9saXN0LCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIpCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gZmVhdHVyZV9saXN0KStSb3RhdGVkQXhpcygpCgoKbWF0X25ldXJvbiA9IGMoIlJCRk9YMyIsIlNZUCIsIkRMRzQ1IiwiVkFNUDEiLCJWQU1QMiIsIlRVQkIzIiwiU1lUMSIsIkJTTiIsIkhPTUVSMSIsIlNMQzE3QTYiKSAKIyBOZXVOIGlzIEZPWDMgLSBSQkZPWDMKIyBQU0Q5NSBhbHNvIFNQLTkwIG9yIERMRzQKIyBWR0xVVDIgaXMgU0xDMTdBNgpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gbWF0X25ldXJvbiwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQojIGNsdXN0ZXIgNCBhbHNvIHNob3cgbWF0dXJlIG5ldXJvbiBtYXJrZXJzCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gbWF0X25ldXJvbikrUm90YXRlZEF4aXMoKQojIGV4Y2l0YXRvcnkgbmV1cm9uIG1hcmtlcnMKZXggPSBjKCJHUklBMiIsIkdSSUExIiwiR1JJQTQiLCJHUklOMSIsIkdSSU4yQiIsIkdSSU4yQSIsIkdSSU4zQSIsIkdSSU4zIiwiR1JJUDEiLCJDQU1LMkEiKQpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gZXgsIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMikKRG90UGxvdChzZXUucSwgZmVhdHVyZXMgPSBleCkrUm90YXRlZEF4aXMoKQojIGluaGliaXRvcnkgbmV1cm9uIG1hcmtlcnMKaW5oID0gYygiR0FEMSIsIkdBRDIiLCAiR0FUMSIsIlBWQUxCIiwiR0FCUjIiLCJHQUJSMSIsIkdCUlIxIiwiR0FCUkIyIiwiR0FCUkIxIiwiR0FCUkIzIiwiR0FCUkE2IiwiR0FCUkExIiwiR0FCUkE0IiwiVFJBSzIiKQpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gaW5oLCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIpCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gaW5oKStSb3RhdGVkQXhpcygpCiMgY2x1c3RlciA0IGlzIG1vcmUgZXhjaXRhdG9yeSB0aGFuIGluaGJpdG9yeSBidXQgbmVpdGhlciBtYXJrZXIgc2V0IGhhcyBtdWNoIGV4cHJlc3Npb24gCgojIyMgZ2xpYSBtYXJrZXJzCm1pY3JvZ2xpYSA9IGMoIlBUUFJDIiwiQUlGMSIsIkFER1JFMSIpICAjIEFER1JFMSBpcyBhIG1pY3JvZ2xpYSBtYXJrZXIgRjQvODAsIENENDUgaXMgUFRQUkMsIGdlbmUgbmFtZSBJQkExIGlzIEFJRjEKYXN0b2xnTlBDcHJvbWljcm8gPSBjKCJHRkFQIiwiUzEwMEIiLCJTTEMxQTIiLCJNQlAiLCJTT1gxMCIsIlNQUDEiLCJEQ1giLCJORVVST0QxIiwiVEJSMSIsIlBDTkEiLCJNS0k2NyIsIlBUUFJDIiwiQUlGMSIsIkFER1JFMSIpCiMgbm90ZSBHTFQxIGlzIEVBQVQyIHdoaWNoIGlzIFNMQzFBMiBnbHV0YXRtYXRlIHRyYW5zcG9ydGVyCiMgZXBpdGhlbGlhbAplcGkgPSBjKCJIRVMxIiwiSEVTNSIsIlNPWDIiLCJTT1gxMCIsIk5FUyIsIkNESDEiLCJOT1RDSDEiKSAjIGUtY2FkaGVyaW4gaXMgQ0RIMQoKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IGFzdG9sZ05QQ3Byb21pY3JvLCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIpCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gYXN0b2xnTlBDcHJvbWljcm8pK1JvdGF0ZWRBeGlzKCkKIyBjbHVzdGVyIDQgaXMgbW9yZSBleGNpdGF0b3J5IHRoYW4gaW5oYml0b3J5IGJ1dCBuZWl0aGVyIG1hcmtlciBzZXQgaGFzIG11Y2ggZXhwcmVzc2lvbiAKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IGVwaSwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IGVwaSkrUm90YXRlZEF4aXMoKQoKIyBhbHNvIGFkZCBSYWRpYWwgZ2xpYSBtYXJrZXIgb3ZlcmxhcCB3aXRoIEdsaWEgYW5kIE5ldXJvbnMKCmZlYXR1cmVzIDwtIGMoIlBUUFJDIiwiQUlGMSIsIkFER1JFMSIsICJWSU0iLCAiVE5DIiwiUFRQUloxIiwiRkFNMTA3QSIsIkhPUFgiLCJMSUZSIiwKICAgICAgICAgICAgICAiSVRHQjUiLCJJTDZTVCIpCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBmZWF0dXJlcywgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IGZlYXR1cmVzKStSb3RhdGVkQXhpcygpCgoKCgpgYGAKCk5vIFRIIGV4cHJlc3Npb24KCmNsdXN0ZXJzIDUgVklNIGhpZ2hlc3QsIFMxMDAgQiAKQ2x1c3RlciA0IApDbHVzdGVyIDMgaGFzIHNvbWUgY2VsbHMgd2l0aCBoaWdoIE9UWDIsIE5FUyBpbmRpY2F0ZXMgTlBDL1ByZWN1cnNvcnMKQ2x1c3RlciAyIGhhcyBzb21lIFNPWDIgYW5kIFBBWDYgaW5kaWNhdGVzIE5QQywgVkFNUDIgaW5kaWNhdGluZyBuZXVyb25zLCBTMTAwQiBoaWdoZXN0IGFuZCBtb3N0IC0gaW5kaWNhdGVzIGFzdHJvY3l0ZXMsIGFsc28gTUJQIGluZGljYXRlcyBvbGlnb3MKQ2x1c3RlciAxCkNsdXN0ZXIgMCAKCgpMYWJsZSB0aGUgY2x1c3RlcnMgCgpgYGB7cn0KCklkZW50cyhzZXUucSkgPC0gJ1JOQV9zbm5fcmVzLjAuMicKCiNzZXUucSA8LSBCdWlsZENsdXN0ZXJUcmVlKHNldS5xLCByZW9yZGVyID0gVFJVRSwgcmVvcmRlci5udW1lcmljID0gVFJVRSkKdW5pcXVlKHNldS5xJFJOQV9zbm5fcmVzLjAuMikKCmNsdXN0ZXIuaWRzIDwtIGMoIkFzdHJvY3l0ZXMxIiwiQXN0cm9jeXRlczIiLCJQcmVjdXJzb3JzIiwiUkcxIiwiUkcyIiwiRW5kb3RoZWxpYWwiKQoKbmFtZXMoY2x1c3Rlci5pZHMpIDwtIGxldmVscyhzZXUucSkKc2V1LnEgPC0gUmVuYW1lSWRlbnRzKHNldS5xLCBjbHVzdGVyLmlkcykKc2V1LnEkc3ViZ3JvdXBzIDwtIElkZW50cyhzZXUucSkKCiNEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjInLCBsYWJlbCA9IFRSVUUpCkRpbVBsb3Qoc2V1LnEsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCBncm91cC5ieSA9ICdzdWJncm91cHMnLCByZXBlbCA9IFRSVUUpCgojIHNvbWV0aGluZyB3ZWlyZCBpcyBnb2luZyBvbiBpbiB0aGUgb3JkZXIKCiNzYXZlUkRTKHNldS5xLCAiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUGhlbm9JRC9zY1JOQXNlcVNvcnRlZC9vYmpzL0dsaWExTGFibGVkU2V1MzAxMTAyMDIyLlJEUyIpCgoKYGBgCgoKCkNvbXBhcmUgdGhlIEFzdHJvY3l0ZSBncm91cHMgYW5kIGdldCBzb21lIG1hcmtlcnMgZm9yIHN1YiBncm91cHMKCmBgYHtyfQoKCmFzdHJvLnN1Yi5tYXJrZXJzIDwtIEZpbmRNYXJrZXJzKHNldS5xLCBpZGVudC4xID0gIkFzdHJvY3l0ZXMxIiwgaWRlbnQuMiA9ICJBc3Ryb2N5dGVzMiIsIG9ubHkucG9zID0gRkFMU0UpCiN0b3A1IDwtIGFzdHJvLnN1Yi5tYXJrZXJzICU+JSB0b3BfbihuPTUsIHd0ID0gYXZnX2xvZzJGQykKCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBjKCJQTENHMiIsIlBUUFJaMSIsIlNOSEcyNSIsIlZDQU4iLCJMVU0iLCJEQ04iLCJTMTAwNEEiKSwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQoKYXN0cm8yIDwtIHJvd25hbWVzKGFzdHJvLnN1Yi5tYXJrZXJzICU+JSBmaWx0ZXIoYXZnX2xvZzJGQyA8IDAuMDUpKQoKRG90UGxvdChzZXUucSwgZmVhdHVyZXMgPSBjKCJQTENHMiIsIlBUUFJaMSIsIlNOSEcyNSIsIlZDQU4iLCJMVU0iLCJEQ04iLCJTMTAwNEEiKSkgKyBSb3RhdGVkQXhpcygpCgpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gYXN0cm8yWzE6MTVdLCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIpCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gYXN0cm8yWzE6MTVdKSArUm90YXRlZEF4aXMoKQoKCiMgcmFkaWFsIGdsaWEgc3VidHlwaW5nCklkZW50cyhzZXUucSkgPC0gKCdzdWJncm91cHMnKQpyZy5zdWIubWFya2VycyA8LSBGaW5kTWFya2VycyhzZXUucSwgaWRlbnQuMSA9ICJSRzEiLCBpZGVudC4yID0gIlJHMiIsIG9ubHkucG9zID0gRkFMU0UpCnRvcDUudXAgPC0gcmcuc3ViLm1hcmtlcnMgJT4lIHRvcF9uKG49MTAsIHd0ID0gYXZnX2xvZzJGQykKdG9wNS5kb3duIDwtIHJnLnN1Yi5tYXJrZXJzICU+JSB0b3BfbihuPS0xMCwgd3QgPSBhdmdfbG9nMkZDKQpmdCA8LSByb3duYW1lcyh0b3A1LnVwKQoKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IGZ0LCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIpCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gZnQpICsgUm90YXRlZEF4aXMoKQoKCmZ0IDwtIHJvd25hbWVzKHRvcDUuZG93bikKCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBmdCwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IGZ0KSArIFJvdGF0ZWRBeGlzKCkKCm5wYy5tYXJrZXJzIDwtIEZpbmRNYXJrZXJzKHNldS5xLCBpZGVudC4xID0gIlByZWN1cnNvcnMiLCBpZGVudC4yID0gYygiQXN0cm9jeXRlczIiLCJBc3Ryb2N5dGVzMSIpLCBvbmx5LnBvcyA9IEZBTFNFKQp0b3AxMC5ucGMgPC0gbnBjLm1hcmtlcnMgJT4lIHRvcF9uKG49MTAsIHd0ID0gYXZnX2xvZzJGQykKbnBjLm1hcmtlcnMgPC0gbnBjLm1hcmtlcnMgJT4lIGZpbHRlcihhdmdfbG9nMkZDID4gMCkKZGltKG5wYy5tYXJrZXJzKQoKZnQgPC0gcm93bmFtZXModG9wMTAubnBjKQojIGNvbnNpZGVyIG5hbWluZyBwcmVjdXJzb3JzIGFzIGFzdHJvY3l0ZXMzCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBmdCwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IGZ0KSArIFJvdGF0ZWRBeGlzKCkKCgpucGMubWFya2Vycy5yZyA8LSBGaW5kTWFya2VycyhzZXUucSwgaWRlbnQuMSA9ICJQcmVjdXJzb3JzIiwgaWRlbnQuMiA9IGMoIlJHMiIsIlJHMSIpLCBvbmx5LnBvcyA9IFRSVUUpCnRvcDEwLm5wYyA8LSBucGMubWFya2Vycy5yZyAlPiUgdG9wX24obj0xMCwgd3QgPSBhdmdfbG9nMkZDKQoKZnQgPC0gcm93bmFtZXModG9wMTAubnBjKQojIGNvbnNpZGVyIG5hbWluZyBwcmVjdXJzb3JzIGFzIGFzdHJvY3l0ZXMzCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBmdCwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IGZ0KSArIFJvdGF0ZWRBeGlzKCkKCiMjIHRoZXNlIGhhdmUgbW9yZSBkaWZmZXJlbmNlcyBmcm9tIFJHIHRoYW4gQXN0cm9jeXRlcwoKCmBgYAoKQWRkIHN1YnR5cGUgZ2VuZSBpZHMKCmBgYHtyfQoKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC4yJykKCmNsdXN0ZXIuaWRzIDwtIGMoIkFzdHJvY3l0ZXMtUExDRzIiLCJBc3Ryb2N5dGVzLUROQyIsIkFzdHJvY3l0ZXMtSUdGQlAyIiwKICAgICAgICAgICAgICAgICAiUkcxLUNES04xQyIsIlJHMi1UWVJQMSIsIkVuZG90aGVsaWFsIikKI2NsdXN0ZXIuaWRzIDwtIGMoIkFzdHJvY3l0ZXMxIiwiQXN0cm9jeXRlczIiLCJQcmVjdXJzb3JzKEFzdHJvY3l0ZXMpIiwiUkcxIiwiUkcyIiwiRW5kb3RoZWxpYWwiKQoKbmFtZXMoY2x1c3Rlci5pZHMpIDwtIGxldmVscyhzZXUucSkKc2V1LnEgPC0gUmVuYW1lSWRlbnRzKHNldS5xLCBjbHVzdGVyLmlkcykKc2V1LnEkQ2VsbF90eXBlcyA8LSBJZGVudHMoc2V1LnEpCgpEaW1QbG90KHNldS5xLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgZ3JvdXAuYnkgPSAnQ2VsbF90eXBlcycsIHJlcGVsID0gVFJVRSkKCgpzYXZlUkRTKHNldS5xLCAiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUGhlbm9JRC9zY1JOQXNlcVNvcnRlZC9vYmpzL0dsaWExTGFibGVkU2V1MzAxMTAyMDIyLlJEUyIpCgojIGxhYmVsIHdpdGggbWFpbiBjZWxsIHR5cGUgZ3JvdXBzIAoKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC4yJykKCmNsdXN0ZXIuaWRzIDwtIGMoIkFzdHJvY3l0ZXMiLCJBc3Ryb2N5dGVzIiwiQXN0cm9jeXRlcyIsCiAgICAgICAgICAgICAgICAgIlJHIiwiUkciLCJFbmRvdGhlbGlhbCIpCiNjbHVzdGVyLmlkcyA8LSBjKCJBc3Ryb2N5dGVzMSIsIkFzdHJvY3l0ZXMyIiwiUHJlY3Vyc29ycyhBc3Ryb2N5dGVzKSIsIlJHMSIsIlJHMiIsIkVuZG90aGVsaWFsIikKCm5hbWVzKGNsdXN0ZXIuaWRzKSA8LSBsZXZlbHMoc2V1LnEpCnNldS5xIDwtIFJlbmFtZUlkZW50cyhzZXUucSwgY2x1c3Rlci5pZHMpCnNldS5xJENlbGxfVHlwZSA8LSBJZGVudHMoc2V1LnEpCgpEaW1QbG90KHNldS5xLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgZ3JvdXAuYnkgPSAnQ2VsbF9UeXBlJywgcmVwZWwgPSBUUlVFKQoKCnNhdmVSRFMoc2V1LnEsICIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QaGVub0lEL3NjUk5Bc2VxU29ydGVkL29ianMvR2xpYTFMYWJsZWRTZXUzMDExMDIwMjIuUkRTIikKCgoKCmBgYAoKCkxhYmVsIG1haW4gY2VsbCB0eXBlcyAKUmVzIDAuOAlwcmVkaWNpdG9ucwowCWFzdHJvCjEJRW5kby9SRy9Bc3RybwoyCUFzdHJvY3l0ZQozCVJHL0VuZG8vQXN0cm8KNAlBc3Rybwo1CUFzdHJvCjYJRXBpdGhlbGEsIGVuZG8sIGFzdHJvLCBSRwo3CUFzdHJvCjgJQXN0cm8KOQlBc3Ryby9SRy9FbmRvCjEwCUFzdHJvL1JHCjExCUFzdHJvL05ldXJvbnMKMTIJRW5kby9SRy4gCgoKYGBge3J9CgojRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC44JykKSWRlbnRzKHNldS5xKSA8LSAnUk5BX3Nubl9yZXMuMC44JwoKY2x1c3Rlci5pZHMgPC0gYygiQXN0cm9jeXRlcyIsIkFzdHJvY3l0ZXMtRW5kby1SRyIsIkFzdHJvY3l0ZXMiLAogICAgICAgICAgICAgICAgICJSRy1FbmRvLUFzdHJvIiwiQXN0cm8iLCJBc3RybyIsIkVwaS1FbmRvLUFzdHJvLVJHIiwKICAgICAgICAgICAgICAgICAiQXN0cm8iLCJBc3RybyIsIkFzdHJvLVJHLUVuZG8iLCJBc3Ryby1SRyIsIkFzdHJvLU5ldXJvbnMiLCJFbmRvLVJHIikKCmNsdXN0ZXIuaWRzIDwtIGMoIkFzdHJvY3l0ZXMiLCJBc3Ryb2N5dGVzIiwiQXN0cm9jeXRlcyIsCiAgICAgICAgICAgICAgICAgIkFzdHJvY3l0ZXMiLCJBc3Ryb2N5dGVzIiwiQXN0cm9jeXRlcyIsIkVuZG90aGVsaWFsIiwKICAgICAgICAgICAgICAgICAiQXN0cm9jeXRlcyIsIkFzdHJvY3l0ZXMiLCJSYWRpYWwgR2xpYSIsIlJhZGlhbCBHbGlhIiwiQXN0cm9jeXRlcyIsIkVuZG90aGVsaWFsIikKCm5hbWVzKGNsdXN0ZXIuaWRzKSA8LSBsZXZlbHMoc2V1LnEpCnNldS5xIDwtIFJlbmFtZUlkZW50cyhzZXUucSwgY2x1c3Rlci5pZHMpCnNldS5xJENlbGxfVHlwZSA8LSBJZGVudHMoc2V1LnEpCgpEaW1QbG90KHNldS5xLCByZWR1Y3Rpb24gPSAidW1hcCIsIGxhYmVsID0gVFJVRSwgZ3JvdXAuYnkgPSAnQ2VsbF9UeXBlJywgcmVwZWwgPSBUUlVFKQoKCnNhdmVSRFMoc2V1LnEsICIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QaGVub0lEL3NjUk5Bc2VxU29ydGVkL29ianMvR2xpYTFMYWJsZWRTZXUzMDExMDIwMjIuUkRTIikKCgoKYGBgCgpgYGB7cn0KdGFibGUoc2V1LnEkQ2VsbF9UeXBlKQoKYGBgCgoKClF1aWNrIGNoZWNrIHRoZSBHbGlhbDIgCgpgYGB7cn0KCiMgZXhwbG9yZSBmaWx0ZXJpbmcKc2V1IDwtIEdsaWEyCnNldQojIApWbG5QbG90KHNldSwgcHQuc2l6ZSA9IDAuMTAsIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiwgIm5Db3VudF9STkEiLCAicGVyY2VudC5tdCIpLCBuY29sID0gMykKClZsblBsb3Qoc2V1LCBwdC5zaXplID0gMC4xMCwgZmVhdHVyZXMgPSBjKCJuRmVhdHVyZV9STkEiKSwgeS5tYXggPSAxMDAwKQpWbG5QbG90KHNldSwgcHQuc2l6ZSA9IDAuMTAsIGZlYXR1cmVzID0gYygibkZlYXR1cmVfUk5BIiksIHkubWF4ID0gNTAwKQpWbG5QbG90KHNldSwgcHQuc2l6ZSA9IDAuMTAsIGZlYXR1cmVzID0gYygibkNvdW50X1JOQSIpLCB5Lm1heCA9IDIwMDApCgojIGZpbHRlciBtb3JlIGNlbGxzCgpzZXUuZnQgPC0gc3Vic2V0KHNldSwgc3Vic2V0ID0gbkZlYXR1cmVfUk5BID4gMjUwICYgbkNvdW50X1JOQSA+IDI1MCAmIG5Db3VudF9STkEgPCAxMDAwMCkgCnNldS5mdAoKVmxuUGxvdChzZXUuZnQsIHB0LnNpemUgPSAwLjEwLCBmZWF0dXJlcyA9IGMoIm5GZWF0dXJlX1JOQSIpLCB5Lm1heCA9IDIwMDApCgpgYGAKYGBge3J9CgpWbG5QbG90KHNldS5mdC5nbGlhLCBmZWF0dXJlcyA9IGMoIkNENDQiLCJTMTAwQiIsIklUR0IxIikpClZsblBsb3Qoc2V1LmZ0LCBmZWF0dXJlcyA9IGMoIkNENDQiLCJTMTAwQiIsIklUR0IxIiksIGdyb3VwLmJ5ID0gJ29yaWcuaWRlbnQnKQojIGJvdGggZ2xpYSBwb3B1bGF0aW9ucyBhcmUgc2ltaWxhcgoKCmBgYAoKTGV2ZWxzIHNlZW0gc2ltaWxhciBpbiBHbGlhMSBhbmQgR2xpYTIKClJlbW92ZSBkb3VibGV0cyBhbmQgc3RhcnQgdG8gcHJvY2VzcyBHbGlhIDIKCmBgYHtyfQoKc3VwcHJlc3NNZXNzYWdlcyhyZXF1aXJlKERvdWJsZXRGaW5kZXIpKQoKIyBmaWx0ZXJpbmcgb3V0IE1BTEFUMSBhbmQgbWl0b2Nob25kcmlhbCBnZW5lcwoKc2V1LmZ0IDwtIHNldS5mdFshZ3JlcGwoIk1BTEFUMSIsIHJvd25hbWVzKHNldS5mdCkpLCBdCnNldS5mdCA8LSBzZXUuZnRbIWdyZXBsKCJeTVQtIiwgcm93bmFtZXMoc2V1LmZ0KSksIF0KCiMgbGlrZSBpbiB0aGUgdHV0b3JpYWwgSSdtIGZvbGxvd2luZyBNQUxBVDEgaXMgdGhlIHRvcCBtb3N0IGV4cHJlc3NlZCBnZW5lLiAgVGhlIHRvcCBnZW5lcyBhcmUgYSBsb3Qgb2YgTVQgYW5kIFJpYm9zb21hbCBnZW5lcwoKc2V1LmZ0W1sicGVyY2VudC5yYiJdXSA8LSBQZXJjZW50YWdlRmVhdHVyZVNldChzZXUuZnQsIHBhdHRlcm4gPSAiXlJQIikKCnNldS5kID0gTm9ybWFsaXplRGF0YShzZXUuZnQpCnNldS5kID0gRmluZFZhcmlhYmxlRmVhdHVyZXMoc2V1LmQsIHZlcmJvc2UgPSBGKQpzZXUuZCA9IFNjYWxlRGF0YShzZXUuZCwgdmFycy50by5yZWdyZXNzID0gYygibkZlYXR1cmVfUk5BIiwgInBlcmNlbnQubXQiKSwKICAgIHZlcmJvc2UgPSBGKQpzZXUuZCA9IFJ1blBDQShzZXUuZCwgdmVyYm9zZSA9IEYsIG5wY3MgPSAxNSkKc2V1LmQgPSBSdW5VTUFQKHNldS5kLCBkaW1zID0gMToxMCwgdmVyYm9zZSA9IEYpCgpuRXhwIDwtIHJvdW5kKG5jb2woc2V1LmQpICogMC4wOCkgICMgZXhwZWN0IG1vcmUgZG91YmxldHMgYmVjYXVzZSB0aGVyZSBpcyBhIGxvdCBtb3JlIGNlbGxzCnNldS5kIDwtIGRvdWJsZXRGaW5kZXJfdjMoc2V1LmQsIHBOID0gMC4yNSwgcEsgPSAwLjA5LCBuRXhwID0gbkV4cCwgUENzID0gMToxMCkKIyB0aGUgbWVtb3J5IGxpbWl0IGlzIHJlYWNoZWQgaGVyZSAtIEkgY291bGQgcnVuIG9uIGNvbXB1dGUgY2FuYWRhCiMgRm9yIG5vdyBJJ2xsIGRvd25zYW1wbGUKIyB0aGlzIHdvcmtzCgojIG5hbWUgb2YgdGhlIERGIHByZWRpY3Rpb24gY2FuIGNoYW5nZSwgc28gZXh0cmFjdCB0aGUgY29ycmVjdCBjb2x1bW4gbmFtZS4KREYubmFtZSA9IGNvbG5hbWVzKHNldS5kQG1ldGEuZGF0YSlbZ3JlcGwoIkRGLmNsYXNzaWZpY2F0aW9uIiwgY29sbmFtZXMoc2V1LmRAbWV0YS5kYXRhKSldCgoKY293cGxvdDo6cGxvdF9ncmlkKG5jb2wgPSAyLCBEaW1QbG90KHNldS5kLCBncm91cC5ieSA9ICJvcmlnLmlkZW50IikgKyBOb0F4ZXMoKSwKICAgIERpbVBsb3Qoc2V1LmQsIGdyb3VwLmJ5ID0gREYubmFtZSkgKyBOb0F4ZXMoKSkKClZsblBsb3Qoc2V1LmQsIGZlYXR1cmVzID0gIm5GZWF0dXJlX1JOQSIsIGdyb3VwLmJ5ID0gREYubmFtZSwgcHQuc2l6ZSA9IDAuMSkKCmBgYAoKCmBgYHtyfQoKc2V1LmQgPC0gc2V1LmRbLCBzZXUuZEBtZXRhLmRhdGFbLCBERi5uYW1lXT09ICJTaW5nbGV0Il0KZGltKHNldS5kKQpkaW0oc2V1LmZ0KQoKCgpgYGAKCkNsdXN0ZXIgCgpgYGB7cn0Kc2V1IDwtIE5vcm1hbGl6ZURhdGEoc2V1LmQsIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIkxvZ05vcm1hbGl6ZSIsIHNjYWxlLmZhY3RvciA9IDEwMDAwKQpzZXUgPC0gRmluZFZhcmlhYmxlRmVhdHVyZXMoc2V1LCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCnNldSA8LSBTY2FsZURhdGEoc2V1KQpzZXUgPC0gUnVuUENBKHNldSkKc2V1IDwtIFJ1blVNQVAoc2V1LCByZWR1Y3Rpb24gPSAicGNhIiwgbi5uZWlnaGJvcnMgPSAyNSwgZGltcyA9IDE6MzApCkRpbVBsb3Qoc2V1LCByZWR1Y3Rpb24gPSAidW1hcCIpCgpzZXUucSA8LSBGaW5kTmVpZ2hib3JzKHNldSwgZGltcyA9IDE6MjUsIGsucGFyYW0gPSAyNSkKc2V1LnEgPC0gRmluZENsdXN0ZXJzKHNldS5xLCByZXNvbHV0aW9uID0gYygwLDAuMDUsMC4yLDAuNCwwLjUsMC42LDAuOCkpCmxpYnJhcnkoY2x1c3RyZWUpCgpEaW1QbG90KHNldS5xLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjAuMDUnKQpEaW1QbG90KHNldS5xLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjAuMScpCkRpbVBsb3Qoc2V1LnEsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC4yJykKRGltUGxvdChzZXUucSwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjQnKQpEaW1QbG90KHNldS5xLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjAuNicpCkRpbVBsb3Qoc2V1LnEsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAnUk5BX3Nubl9yZXMuMC44JykKY2x1c3RyZWUoc2V1LnEpCiMgMC40IGlzIGxpa2VseSB0aGUgYmVzdCBhbm5vdGF0ZSBzdWJncm91cHMKCgpgYGAKClByZWRpY3QgY2VsbCB0eXBlcyAKCgpgYGB7cn0KCiMgU05DQSBhbmQgY29udHJvbCBtaWRicmFpbiBvcmdhbm9pZHMgMTY1IGRheXMgaW4gY3VsdHVyZQpNQk8gPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvQVNUMjNfQnJhaW5Db21tL01CT2NsdXN0ZXJzX25hbWVzMjkwNzIwMjEucmRzIikKCiMgTWlkYnJhaW4gIEFJVzAwMiAxMjAgZGF5cyBpbiBjdWx0dXJlCkFJV01CTyA8LSByZWFkUkRTKCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9BSVd0cmlvMTIwZGF5cy9NT2ludGVncmF0ZWRDbHVzdGVySzEyM3JlczAuOC5uYW1lc19ub3YxNl8yMDIxIikKCiMgTWlkYnJhaW4gQUlXMDAyIDYwIGRheXMgaW4gY3VsdHVyZQoKQUlXNjAgPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvQUlXdHJpbzYwZGF5cy9BV0kwMDJQYXJraW5LT1BpbmtLTzYwZGF5c19sYWJlbHNfMTQwNTIwMjIucmRzIikKCgojZmlyc3QgcHJlZGljdCB3aXRoIHRoZSBNQk8gZGF0YQpJZGVudHMoTUJPKSA8LSAiY2x1c3Rlcl9sYWJlbHMiCkRlZmF1bHRBc3NheShNQk8pIDwtICJSTkEiCgojIGZpbmQgdGhlIHJlZmVyZW5jZSBhbmNob3JzCnByaW50KCJmaW5kaW5nIHJlZmVyZW5jZSBhbmNob3JzIikKYW5jaG9ycyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKHJlZmVyZW5jZSA9IE1CTyAscXVlcnkgPSBzZXUucSwgZGltcyA9IDE6MjUpCnByaW50KCJnZXR0aW5nIHByZWRpY3Rpb25zIikKcHJlZGljdGlvbnMgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IGFuY2hvcnMsIHJlZmRhdGEgPSBNQk8kY2x1c3Rlcl9sYWJlbHMpCnNldS5xIDwtIEFkZE1ldGFEYXRhKHNldS5xLCBtZXRhZGF0YSA9IHByZWRpY3Rpb25zKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwojIGFkZCBuZXcgZGF0YXNsb3QgZm9yIE1CTyBwcmVkaWN0ZWQgSUQgdG8gbWFrZSB0aGUgbmV4dCBwcmVkaWN0aW9uCnNldS5xJE1CT0FTVDIzLnByZWQgPC0gSWRlbnRzKHNldS5xKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdNQk9BU1QyMy5wcmVkJywgbGFiZWwgPSBUUlVFKQoKIyBzZWUgaG93IGFjY3VyYXRlIHRoZSBwcmVkaWN0aW9ucyBhcmUKc2V1LnEkcHJlZGljdGVkLmlkIDwtIGlmZWxzZShzZXUucSRwcmVkaWN0aW9uLnNjb3JlLm1heCA+IDAuOTUsIHNldS5xJHByZWRpY3RlZC5pZCwgIk5vbmUiKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwpzZXUucSRNQk9BU1QyMy50aHJlc2ggPC0gSWRlbnRzKHNldS5xKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdwcmVkaWN0ZWQuaWQnLCBsYWJlbCA9IFRSVUUpCnRhYmxlKHNldS5xJE1CT0FTVDIzLnByZWQpCnRhYmxlKHNldS5xJE1CT0FTVDIzLnRocmVzaCkKCgogCiMjIGNoZWNrIHRoZSBwcm9wb3J0aW9uIG9mIGNlbGwgdHlwZXMgcHJlZGljdGVkIGluIGVhY2ggY2x1c3Rlcgp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuNCwgc2V1LnEkTUJPQVNUMjMucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCgojIHRyeSBiYXIgY2hhcnQKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKQoKIyBjbHVzdGVycyBkb24ndCBicmVhayB1cCBieSB0aGUgcHJlZGljdGVkIGNlbGwgdHlwZXMKCiMjIyMjIyMjIyMjIyBhbm90aGVyIHByZWRpY3Rpb25zIG5vdyB1c2luZyB0aGUgQUlXIG9yZ2Fub2lkcwoKSWRlbnRzKEFJV01CTykgPC0gInJlczA4bmFtZXMiCkRlZmF1bHRBc3NheShBSVdNQk8pIDwtICJSTkEiCgphbmNob3JzIDwtIEZpbmRUcmFuc2ZlckFuY2hvcnMocmVmZXJlbmNlID0gQUlXTUJPICxxdWVyeSA9IHNldS5xLCBkaW1zID0gMToyNSkKcHJpbnQoImdldHRpbmcgcHJlZGljdGlvbnMiKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IEFJV01CTyRyZXMwOG5hbWVzKQpzZXUucSA8LSBBZGRNZXRhRGF0YShzZXUucSwgbWV0YWRhdGEgPSBwcmVkaWN0aW9ucykKcHJpbnQodGFibGUoc2V1LnEkcHJlZGljdGVkLmlkKSkKCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKIyBhZGQgbmV3IGRhdGFzbG90IGZvciBNQk8gcHJlZGljdGVkIElEIHRvIG1ha2UgdGhlIG5leHQgcHJlZGljdGlvbgpzZXUucSRBSVcxMjAucHJlZCA8LSBJZGVudHMoc2V1LnEpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ0FJVzEyMC5wcmVkJywgbGFiZWwgPSBUUlVFKQogCiMjIGNoZWNrIHRoZSBwcm9wb3J0aW9uIG9mIGNlbGwgdHlwZXMgcHJlZGljdGVkIGluIGVhY2ggY2x1c3Rlcgp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuNCwgc2V1LnEkTUJPQUlXLnByZWQpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQojIHRyeSBiYXIgY2hhcnQKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKQoKIyBzZWUgaG93IGFjY3VyYXRlIHRoZSBwcmVkaWN0aW9ucyBhcmUKc2V1LnEkcHJlZGljdGVkLmlkIDwtIGlmZWxzZShzZXUucSRwcmVkaWN0aW9uLnNjb3JlLm1heCA+IDAuOTUsIHNldS5xJHByZWRpY3RlZC5pZCwgIk5vbmUiKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwpzZXUucSRBSVcxMjAudGhyZXNoIDwtIElkZW50cyhzZXUucSkKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnQUlXMTIwLnRocmVzaCcsIGxhYmVsID0gVFJVRSkKdGFibGUoc2V1LnEkQUlXMTIwLnByZWQpCnRhYmxlKHNldS5xJEFJVzEyMC50aHJlc2gpCgojIHRoZSBwcmVkaWN0ZWQgY2VsbCB0eXBlcyBtYWtlIG1vcmUgc2Vuc2UgZnJvbSB0aGUgQUlXMDAyIG9yZ2Fub2lkCiMgbm93IHByZWRpY3Qgd2l0aCB0aGUgQUlXMDAyIDYwIGRheXMgb3JnYW5vaWQKCklkZW50cyhBSVc2MCkgPC0gImNsdXN0ZXIuaWRzIgpEZWZhdWx0QXNzYXkoQUlXNjApIDwtICJSTkEiCgphbmNob3JzIDwtIEZpbmRUcmFuc2ZlckFuY2hvcnMocmVmZXJlbmNlID0gQUlXNjAsIHF1ZXJ5ID0gc2V1LnEsIGRpbXMgPSAxOjI1KQpwcmludCgiZ2V0dGluZyBwcmVkaWN0aW9ucyIpCnByZWRpY3Rpb25zIDwtIFRyYW5zZmVyRGF0YShhbmNob3JzZXQgPSBhbmNob3JzLCByZWZkYXRhID0gQUlXNjAkY2x1c3Rlci5pZHMpIApzZXUucSA8LSBBZGRNZXRhRGF0YShzZXUucSwgbWV0YWRhdGEgPSBwcmVkaWN0aW9ucykKcHJpbnQodGFibGUoc2V1LnEkcHJlZGljdGVkLmlkKSkKCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKIyBhZGQgbmV3IGRhdGFzbG90IGZvciBNQk8gcHJlZGljdGVkIElEIHRvIG1ha2UgdGhlIG5leHQgcHJlZGljdGlvbgpzZXUucSRBSVc2MC5wcmVkIDwtIElkZW50cyhzZXUucSkKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnQUlXNjAucHJlZCcsIGxhYmVsID0gVFJVRSkKIAojIyBjaGVjayB0aGUgcHJvcG9ydGlvbiBvZiBjZWxsIHR5cGVzIHByZWRpY3RlZCBpbiBlYWNoIGNsdXN0ZXIKdC5sYWJsZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4wLjQsIHNldS5xJEFJVzYwLnByZWQpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQoKIyB0cnkgYmFyIGNoYXJ0CmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikKCiMgc2VlIGhvdyBhY2N1cmF0ZSB0aGUgcHJlZGljdGlvbnMgYXJlCnNldS5xJHByZWRpY3RlZC5pZCA8LSBpZmVsc2Uoc2V1LnEkcHJlZGljdGlvbi5zY29yZS5tYXggPiAwLjk1LCBzZXUucSRwcmVkaWN0ZWQuaWQsICJOb25lIikKCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKc2V1LnEkQUlXNjAudGhyZXNoIDwtIElkZW50cyhzZXUucSkKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnQUlXNjAudGhyZXNoJywgbGFiZWwgPSBUUlVFKQp0YWJsZShzZXUucSRBSVc2MC5wcmVkKQp0YWJsZShzZXUucSRBSVc2MC50aHJlc2gpCgoKCiMgbW9zdCBvZiB0aGUgY2VsbHMgYXJlIHByZWRpY3RlZCBhcyBOUENzIGluIG1hbnkgcG9wdWxhdGlvbnMKCgoKYGBgCgpgYGB7cn0KIyBzYXZlIHdpdGggcHJlZGljdGlvbnMgc28gZmFyCiNzYXZlUkRTKHNldS5xLCAiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUGhlbm9JRC9zY1JOQXNlcVNvcnRlZC9vYmpzL0dsaWEyTGFibGVkU2V1MDMxMDIwMjIuUkRTIikKCnNldS5xIDwtIHJlYWRSRFMoIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BoZW5vSUQvc2NSTkFzZXFTb3J0ZWQvb2Jqcy9HbGlhMkxhYmxlZFNldTAzMTAyMDIyLlJEUyIpCgoKYGBgCgoKU2VlIGhvdyBtYW55IGNlbGxzIGFyZSBwcmVkaWN0ZWQgYXMgYXN0cm9jeXRlcyB3aXRoIHRoZSB0aHJlc2hvbGQKCmBgYHtyfQoKREFzdWJ0eXBlcyA8LSByZWFkUkRTKCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9NYWNvc2tvX0RhdGEvREFzdWJncm91cHNfcHJvY2Vzc2VkLlJkcyIpCgpJZGVudHMoYXN0cm8ucmVmKSA8LSAiQ2VsbF9TdWJ0eXBlIgpEZWZhdWx0QXNzYXkoYXN0cm8ucmVmKSA8LSAiUk5BIgoKIyBmaW5kIHRoZSByZWZlcmVuY2UgYW5jaG9ycwpwcmludCgiZmluZGluZyByZWZlcmVuY2UgYW5jaG9ycyIpCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBEQXN1YnR5cGVzICxxdWVyeSA9IHNldS5xLCBkaW1zID0gMToyMCkKcHJpbnQoImdldHRpbmcgcHJlZGljdGlvbnMiKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IGFzdHJvLnJlZiRDZWxsX1N1YnR5cGUsIGsud2VpZ2h0ID0gMTApCnNldS5xIDwtIEFkZE1ldGFEYXRhKHNldS5xLCBtZXRhZGF0YSA9IHByZWRpY3Rpb25zKQpwcmludCh0YWJsZShzZXUucSRwcmVkaWN0ZWQuaWQpKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwojIGFkZCBuZXcgZGF0YXNsb3QgZm9yIE1CTyBwcmVkaWN0ZWQgSUQgdG8gbWFrZSB0aGUgbmV4dCBwcmVkaWN0aW9uCnNldS5xJGFzdHJvLnByZWQgPC0gSWRlbnRzKHNldS5xKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdhc3Ryby5wcmVkJywgbGFiZWwgPSBUUlVFKQp0YWJsZShzZXUucSRhc3Ryby5wcmVkKQoKc2V1LnEkcHJlZGljdGVkLmlkIDwtIGlmZWxzZShzZXUucSRwcmVkaWN0aW9uLnNjb3JlLm1heCA+IDAuOTUsIHNldS5xJHByZWRpY3RlZC5pZCwgIm5vbmUiKQpwcmludCh0YWJsZShzZXUucSRwcmVkaWN0ZWQuaWQpKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwpzZXUucSRhc3Ryby5wcmVkLnRocmVzaCA8LSBJZGVudHMoc2V1LnEpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ2FzdHJvLnByZWQudGhyZXNoJywgbGFiZWwgPSBUUlVFKQp0YWJsZShzZXUucSRhc3Ryby5wcmVkLnRocmVzaCkKCgp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuMiwgc2V1LnEkYXN0cm8ucHJlZC50aHJlc2gpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuYXN0cm8gPC0gYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oMiwgRnJlcSkpCmRmLnRvcC5hc3RybyA8LSB0b3AucHJlZC5hc3Ryb1tvcmRlcih0b3AucHJlZC5hc3RybyRWYXIxLC10b3AucHJlZC5hc3RybyRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3AuYXN0cm8pIDwtIE5VTEwKCgp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuMiwgc2V1LnEkYXN0cm8ucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5hc3RybyA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLmFzdHJvIDwtIHRvcC5wcmVkLmFzdHJvW29yZGVyKHRvcC5wcmVkLmFzdHJvJFZhcjEsLXRvcC5wcmVkLmFzdHJvJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5hc3RybykgPC0gTlVMTAoKIyBhIGxvdCBvZiB0aGVzZSBjZWxscyBhcmUgYWxzbyBnZXR0aW5nIGxhYmVsbGVkIGFzIGFzdHJvY3l0ZXMKCgpgYGAKCkRvIHRoZXNlIGdldCBsYWJlbGxlZCBhcyBEQSBuZXVyb25zIHRvbz8/PwoKYGBge3J9CnNldS5xIDwtIHJlYWRSRFMoIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BoZW5vSUQvc2NSTkFzZXFTb3J0ZWQvb2Jqcy9HbGlhMkxhYmxlZFNldTAzMTAyMDIyLlJEUyIpCgpgYGAKCgoKYGBge3J9CgpEQXN1YnR5cGVzIDwtIHJlYWRSRFMoIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL01hY29za29fRGF0YS9EQXN1Ymdyb3Vwc19wcm9jZXNzZWQuUmRzIikKSWRlbnRzKERBc3VidHlwZXMpIDwtICJDZWxsX1N1YnR5cGUiCmRhLnJlZiA8LSBzdWJzZXQoREFzdWJ0eXBlcywgZG93bnNhbXBsZSA9IDUwMCkKCiMgZmluZCB0aGUgcmVmZXJlbmNlIGFuY2hvcnMKcHJpbnQoImZpbmRpbmcgcmVmZXJlbmNlIGFuY2hvcnMiKQphbmNob3JzIDwtIEZpbmRUcmFuc2ZlckFuY2hvcnMocmVmZXJlbmNlID0gZGEucmVmLCBxdWVyeSA9IHNldS5xLCBkaW1zID0gMToyMCkKcHJpbnQoImdldHRpbmcgcHJlZGljdGlvbnMiKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IGRhLnJlZiRDZWxsX1N1YnR5cGUsIGsud2VpZ2h0ID0gMTApCnNldS5xIDwtIEFkZE1ldGFEYXRhKHNldS5xLCBtZXRhZGF0YSA9IHByZWRpY3Rpb25zKQpwcmludCh0YWJsZShzZXUucSRwcmVkaWN0ZWQuaWQpKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwojIGFkZCBuZXcgZGF0YXNsb3QgZm9yIE1CTyBwcmVkaWN0ZWQgSUQgdG8gbWFrZSB0aGUgbmV4dCBwcmVkaWN0aW9uCnNldS5xJGRhLnByZWQgPC0gSWRlbnRzKHNldS5xKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdkYS5wcmVkJywgbGFiZWwgPSBUUlVFKQp0YWJsZShzZXUucSRkYS5wcmVkKQoKc2V1LnEkcHJlZGljdGVkLmlkIDwtIGlmZWxzZShzZXUucSRwcmVkaWN0aW9uLnNjb3JlLm1heCA+IDAuOTUsIHNldS5xJHByZWRpY3RlZC5pZCwgIm5vbmUiKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwpzZXUucSRkYS5wcmVkLnRocmVzaCA8LSBJZGVudHMoc2V1LnEpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ2RhLnByZWQudGhyZXNoJywgbGFiZWwgPSBUUlVFKQp0YWJsZShzZXUucSRkYS5wcmVkLnRocmVzaCkKCgp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuMiwgc2V1LnEkZGEucHJlZC50aHJlc2gpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuYXN0cm8gPC0gYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oMiwgRnJlcSkpCmRmLnRvcC5hc3RybyA8LSB0b3AucHJlZC5hc3Ryb1tvcmRlcih0b3AucHJlZC5hc3RybyRWYXIxLC10b3AucHJlZC5kYSRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3AuYXN0cm8pIDwtIE5VTEwKCgp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuMiwgc2V1LnEkYXN0cm8ucHJlZCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5hc3RybyA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLmFzdHJvIDwtIHRvcC5wcmVkLmFzdHJvW29yZGVyKHRvcC5wcmVkLmFzdHJvJFZhcjEsLXRvcC5wcmVkLmFzdHJvJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5hc3RybykgPC0gTlVMTAoKCiMgYWZ0ZXIgdGhyZXNob2xkaW5nIHZlcnkgZmV3IGNlbGxzIGFyZSBwcmVkaWN0ZWQgYXMgbmV1cm9ucwoKCgpgYGAKCntyZWRpY3RlIHdpdGggdGhlIGJyYWluIHNjUk5Bc2VxCgpgYGB7cn0KCnBhdGh3YXkgPC0gIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BoZW5vSUQvc2NSTkFzZXFTb3J0ZWQvb2Jqcy8iCnNldS5xIDwtIHJlYWRSRFMocGFzdGUocGF0aHdheSwiR2xpYTJMYWJsZWRTZXUwMzEwMjAyMi5SRFMiLHNlcCA9ICIiKSkKCiMgbWlkYnJhaW4gYW5kIHN0cmlhdHVtCgpzZXUuciA8LSByZWFkUkRTKCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QdWJsaWNEYXRhL0JoYWR1cmlfd2hvbGVCcmFpbi9CaGFkdXJpX21pZGJyYWluX3N0cmlhdHVtLlJEUyIpCgpJZGVudHMoc2V1LnIpIDwtICJjZWxsX2NsdXN0ZXIiCgojIGZpbmQgdGhlIHJlZmVyZW5jZSBhbmNob3JzCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBzZXUuciwgcXVlcnkgPSBzZXUucSwgZGltcyA9IDE6MjUpCnByaW50KCJnZXR0aW5nIHByZWRpY3Rpb25zIikKcHJlZGljdGlvbnMgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IGFuY2hvcnMsIHJlZmRhdGEgPSBzZXUuciRjZWxsX2NsdXN0ZXIpCnNldS5xIDwtIEFkZE1ldGFEYXRhKHNldS5xLCBtZXRhZGF0YSA9IHByZWRpY3Rpb25zKQpwcmludCh0YWJsZShzZXUucSRwcmVkaWN0ZWQuaWQpKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwpzZXUucSRCaGEubWlkLnN0cmkucHJlZCA8LSBJZGVudHMoc2V1LnEpCnByaW50KHRhYmxlKHNldS5xJEJoYS5taWQuc3RyaS5wcmVkKSkKCgpzZXUucSRwcmVkaWN0ZWQuaWQgPC0gaWZlbHNlKHNldS5xJHByZWRpY3Rpb24uc2NvcmUubWF4ID4gMC45NSwgc2V1LnEkcHJlZGljdGVkLmlkLCAibm9uZSIpCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKc2V1LnEkQmhhLm1pZC5wcmVkLnRocmVzaCA8LSBJZGVudHMoc2V1LnEpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ0JoYS5taWQucHJlZC50aHJlc2gnLCBsYWJlbCA9IFRSVUUpCnRhYmxlKHNldS5xJEJoYS5taWQucHJlZC50aHJlc2gpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ0JoYS5taWQucHJlZC50aHJlc2gnKQoKCiMgcmVhZCBpbiB0aGUgcmVmZXJlbmNlIGRhdGFzZXQKIyB3aG9sZSBicmFpbiBCaGFkdXJpIGRvd24gc2FtcGxlZApzZXUuciA8LSByZWFkUkRTKCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QdWJsaWNEYXRhL0JoYWR1cmlfd2hvbGVCcmFpbi9CaGFkdXJpX2Rvd25zYW1wbGUuUkRTIikKCklkZW50cyhzZXUucikgPC0gImNlbGxfY2x1c3RlciIKCiMgZmluZCB0aGUgcmVmZXJlbmNlIGFuY2hvcnMKYW5jaG9ycyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKHJlZmVyZW5jZSA9IHNldS5yLCBxdWVyeSA9IHNldS5xLCBkaW1zID0gMToyNSkKcHJpbnQoImdldHRpbmcgcHJlZGljdGlvbnMiKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IHNldS5yJGNlbGxfY2x1c3RlcikKc2V1LnEgPC0gQWRkTWV0YURhdGEoc2V1LnEsIG1ldGFkYXRhID0gcHJlZGljdGlvbnMpCnByaW50KHRhYmxlKHNldS5xJHByZWRpY3RlZC5pZCkpCgpJZGVudHMoc2V1LnEpIDwtICdwcmVkaWN0ZWQuaWQnCnNldS5xJEJoYS5wcmVkIDwtIElkZW50cyhzZXUucSkKcHJpbnQodGFibGUoc2V1LnEkQmhhLnByZWQpKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdCaGEucHJlZCcpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ3N1Ymdyb3VwcycpCgpzZXUucSRwcmVkaWN0ZWQuaWQgPC0gaWZlbHNlKHNldS5xJHByZWRpY3Rpb24uc2NvcmUubWF4ID4gMC45NSwgc2V1LnEkcHJlZGljdGVkLmlkLCAibm9uZSIpCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKc2V1LnEkQmhhLm1pZC5wcmVkLnRocmVzaCA8LSBJZGVudHMoc2V1LnEpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ0JoYS5wcmVkLnRocmVzaCcsIGxhYmVsID0gVFJVRSkKdGFibGUoc2V1LnEkQmhhLm1pZC5wcmVkLnRocmVzaCkKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnQmhhLnByZWQudGhyZXNoJykKCgpgYGAKCgoKQ29tcGFyZSBwcmVkaWN0aW9ucyAtIG1ha2UgYSBwcmVkaWN0aW9ucyB0YWJsZQoKYGBge3J9CgojIEFJVzAwMiAxMjAgZGF5cyBwcmVkaWN0aW9ucyAtIHRha2UgdGhlIHRocmVzaG9sZGVkIG9wdGlvbnMKdC5sYWJsZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4wLjIsIHNldS5xJEFJVzEyMC50aHJlc2gpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQUlXMTIwIDwtIGFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDIsIEZyZXEpKQpkZi50b3AuYWl3MTIwIDwtIHRvcC5wcmVkLmNlbGx0eXBlLkFJVzEyMFtvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5BSVcxMjAkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUuQUlXMTIwJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5haXcxMjApIDwtIE5VTEwKZGYudG9wLmFpdzEyMCRJIDwtIHJvdy5uYW1lcyhkZi50b3AuYWl3MTIwKQoKIyBBSVcwMDIgNjAgZGF5cyBwcmVkaWN0aW9ucwp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuMiwgc2V1LnEkQUlXNjAudGhyZXNoKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKSArIFJvdGF0ZWRBeGlzKCkgCnRvcC5wcmVkLmNlbGx0eXBlLkFJVzYwIDwtYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oMiwgRnJlcSkpCmRmLnRvcC5haXc2MCA8LSB0b3AucHJlZC5jZWxsdHlwZS5BSVc2MFtvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5BSVc2MCRWYXIxLC10b3AucHJlZC5jZWxsdHlwZS5BSVc2MCRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3AuYWl3NjApIDwtIE5VTEwKZGYudG9wLmFpdzYwJEkgPC0gcm93Lm5hbWVzKGRmLnRvcC5haXc2MCkKCgojIEFTVDIzIDE2NSBkYXlzIHByZWRpY3Rpb25zCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRNQk9BU1QyMy50aHJlc2gpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQVNUMjMgPC0gYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oMiwgRnJlcSkpCmRmLnRvcC5BU1QyMyA8LSB0b3AucHJlZC5jZWxsdHlwZS5BU1QyM1tvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5BU1QyMyRWYXIxLC10b3AucHJlZC5jZWxsdHlwZS5BU1QyMyRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3AuQVNUMjMpIDwtIE5VTEwKZGYudG9wLkFTVDIzJEkgPC0gcm93Lm5hbWVzKGRmLnRvcC5BU1QyMykKCiMgYWRkIHRoZSB0aHJlc2hvbGQgQXN0cm8gcHJlZGljdGlvbnMgCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRhc3Ryby5wcmVkLnRocmVzaCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5jZWxsdHlwZS5hc3RybyA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLmFzdHJvIDwtIHRvcC5wcmVkLmNlbGx0eXBlLmFzdHJvW29yZGVyKHRvcC5wcmVkLmNlbGx0eXBlLmFzdHJvJFZhcjEsLXRvcC5wcmVkLmNlbGx0eXBlLmFzdHJvJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5hc3RybykgPC0gTlVMTApkZi50b3AuYXN0cm8kSSA8LSByb3cubmFtZXMoZGYudG9wLmFzdHJvKQoKIyBhZGQgdGhlIG5ldXJvbnMgcHJlZGljdGlvbnMgCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRkYS5wcmVkLnRocmVzaCkpCnQubGFibGVzJEZyZXEgPC0gYXMuZG91YmxlKHQubGFibGVzJEZyZXEpCmdncGxvdCh0LmxhYmxlcywgYWVzKHkgPSBGcmVxLCB4ID0gVmFyMSwgZmlsbCA9IFZhcjIpKSArIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIiwgc3RhdD0gImlkZW50aXR5IikgKyBSb3RhdGVkQXhpcygpIAp0b3AucHJlZC5jZWxsdHlwZS5kYSA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLmRhIDwtIHRvcC5wcmVkLmNlbGx0eXBlLmRhW29yZGVyKHRvcC5wcmVkLmNlbGx0eXBlLmRhJFZhcjEsLXRvcC5wcmVkLmNlbGx0eXBlLmRhJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5kYSkgPC0gTlVMTApkZi50b3AuZGEkSSA8LSByb3cubmFtZXMoZGYudG9wLmRhKQoKCiMjIyBhZGQgaW4gdGhlIHByZWRpY3Rpb24gZnJvbSBicmFpbiBkYXRhIEJoYWR1cmkgbWlkYnJhaW4gYW5kIHN0cmlhdHVtCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRCaGEubWlkLnByZWQudGhyZXNoKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKSArIFJvdGF0ZWRBeGlzKCkgCnRvcC5wcmVkLmNlbGx0eXBlLkJoYSA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLkJoYSA8LSB0b3AucHJlZC5jZWxsdHlwZS5CaGFbb3JkZXIodG9wLnByZWQuY2VsbHR5cGUuQmhhJFZhcjEsLXRvcC5wcmVkLmNlbGx0eXBlLkJoYSRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3AuQmhhKSA8LSBOVUxMCmRmLnRvcC5CaGEkSSA8LSByb3cubmFtZXMoZGYudG9wLkJoYSkKCiMjIHRoZXNlIGFyZSBjYWxjdWxhdGVkIGJlbG93CiMjIyBhZGQgaW4gdGhlIHByZWRpY3Rpb24gZnJvbSBicmFpbiB3aG9sZSBicmFpbiBkYXRhIEJoYWR1cmkgbWlkYnJhaW4gZG93biBzYW1wbGVkCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRCaGEucHJlZC50aHJlc2gpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUuQmhhMSA8LSBhcy5kYXRhLmZyYW1lKHQubGFibGVzICAlPiUgZ3JvdXBfYnkoVmFyMSkgICU+JSB0b3BfbigyLCBGcmVxKSkKZGYudG9wLkJoYTEgPC0gdG9wLnByZWQuY2VsbHR5cGUuQmhhMVtvcmRlcih0b3AucHJlZC5jZWxsdHlwZS5CaGEkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUuQmhhJEZyZXEpLF0Kcm93Lm5hbWVzKGRmLnRvcC5CaGExKSA8LSBOVUxMCmRmLnRvcC5CaGExJEkgPC0gcm93Lm5hbWVzKGRmLnRvcC5CaGExKQoKcHJlZC50YWJsZSA8LSBtZXJnZShkZi50b3AuQVNUMjMsIGRmLnRvcC5haXc2MCwgYnkgPSAnSScsIGFsbCA9IFRSVUUpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLmFpdzEyMCwgYnkgPSAnSScpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLkJoYSwgYnkgPSAnSScpCnByZWQudGFibGUgPC0gbWVyZ2UocHJlZC50YWJsZSwgZGYudG9wLkJoYTEsIGJ5ID0gJ0knKQpwcmVkLnRhYmxlCgoKCmBgYAoKUHJlZGljdGVkIGNsdXN0ZXIgYW5ub3RhdGlvbnMKMAlVbmtub3duLyBOUEMKMQlSRwoyCWFzdHJvCjMJUkcKNAluZXVyb25zCjUJUkcKClByZWRpY3QgZnJvbSBkZXZlbG9waW5nIGNvcnRleCAKCmBgYHtyfQoKcGF0aHdheSA8LSAiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUGhlbm9JRC9zY1JOQXNlcVNvcnRlZC9vYmpzLyIKc2V1LnEgPC0gcmVhZFJEUyhwYXN0ZShwYXRod2F5LCJHbGlhMkxhYmxlZFNldTAzMTAyMDIyLlJEUyIsc2VwID0gIiIpKQoKc2V1LnIgPC0gcmVhZFJEUygiL1VzZXJzL3JoYWxlbmF0aG9tYXMvRG9jdW1lbnRzL0RhdGEvc2NSTkFzZXEvUHVibGljRGF0YS9Ob3dha293c2tpX2Rldl9jb3J0ZXh0LlJEUyIpCmNvbG5hbWVzKHNldS5yQG1ldGEuZGF0YSkKCklkZW50cyhzZXUucikgPC0gIldHQ05BY2x1c3RlciIKCiMgZmluZCB0aGUgcmVmZXJlbmNlIGFuY2hvcnMKYW5jaG9ycyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKHJlZmVyZW5jZSA9IHNldS5yLCBxdWVyeSA9IHNldS5xLCBkaW1zID0gMToyNSkKcHJpbnQoImdldHRpbmcgcHJlZGljdGlvbnMiKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IHNldS5yJFdHQ05BY2x1c3RlcikKc2V1LnEgPC0gQWRkTWV0YURhdGEoc2V1LnEsIG1ldGFkYXRhID0gcHJlZGljdGlvbnMpCnByaW50KHRhYmxlKHNldS5xJHByZWRpY3RlZC5pZCkpCgpJZGVudHMoc2V1LnEpIDwtICdwcmVkaWN0ZWQuaWQnCnNldS5xJGRldi5jb3J0ZXgucHJlZCA8LSBJZGVudHMoc2V1LnEpCnByaW50KHRhYmxlKHNldS5xJGRldi5jb3J0ZXgucHJlZCkpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ2Rldi5jb3J0ZXgucHJlZCcpCgoKIyBhZGQgdGhlIHRocmVzaG9sZCAKc2V1LnEkcHJlZGljdGVkLmlkIDwtIGlmZWxzZShzZXUucSRwcmVkaWN0aW9uLnNjb3JlLm1heCA+IDAuOCwgc2V1LnEkcHJlZGljdGVkLmlkLCAibm9uZSIpCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKc2V1LnEkZGV2LmNvcnRleC5wcmVkLnRocmVzaCA8LSBJZGVudHMoc2V1LnEpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ2Rldi5jb3J0ZXgucHJlZC50aHJlc2gnLCBsYWJlbCA9IFRSVUUpCnRhYmxlKHNldS5xJGRldi5jb3J0ZXgucHJlZC50aHJlc2gpCgoKdC5sYWJsZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4wLjIsIHNldS5xJGRldi5jb3J0ZXgucHJlZC50aHJlc2gpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUgPC0gYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oMiwgRnJlcSkpCmRmLnRvcCA8LSB0b3AucHJlZC5jZWxsdHlwZVtvcmRlcih0b3AucHJlZC5jZWxsdHlwZSRWYXIxLC10b3AucHJlZC5jZWxsdHlwZSRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3ApIDwtIE5VTEwKZGYudG9wJEkgPC0gcm93Lm5hbWVzKGRmLnRvcCkKCgojIGFsbW9zdCBldmVyeXRoaW5nIGlzIHByZWRpY3RlZCBhcyAnbm9uZScgd2hlbiB0aGVzaG9sZCBpcyAuOTUgY2hlY2sgcHJlZGljdGlvbnMgd2l0aG91dCB0aHJlc2hvbGQgYW5kIHRoZXJlIGFyZSBtYW55IAojIHJ1biBhZ2FpbiB3aXRoIGxvd2VyIHRocmVzaG9sZCAwLjgKCnQubGFibGVzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkUk5BX3Nubl9yZXMuMC4yLCBzZXUucSRkZXYuY29ydGV4LnByZWQpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUgPC0gYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oNCwgRnJlcSkpCmRmLnRvcCA8LSB0b3AucHJlZC5jZWxsdHlwZVtvcmRlcih0b3AucHJlZC5jZWxsdHlwZSRWYXIxLC10b3AucHJlZC5jZWxsdHlwZSRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3ApIDwtIE5VTEwKZGYudG9wJEkgPC0gcm93Lm5hbWVzKGRmLnRvcCkKCmRmLnRvcC5mdCA8LSBkZi50b3AgJT4lIGZpbHRlcihGcmVxID4gMCkKCgpgYGAKCgpUaGUgZGV2IGNvcnRleCBkb2Vzbid0IHByZWRpY3QgR2xpYSAyIHdlbGwKVHJ5IHRoZSBkZXZlbG9waW5nIGZvcmVicmFpbgoKYGBge3J9CnNldS5yIDwtIHJlYWRSRFMoIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1B1YmxpY0RhdGEvS2Fyb2xpbnNraV9EZXZGb3JlYnJhaW5fZG93bnNhbXBsZV9MZXZlbDEuUkRTIikKY29sbmFtZXMoc2V1LnJAbWV0YS5kYXRhKQpEZWZhdWx0QXNzYXkoc2V1LnIpIDwtICdSTkEnCgojIGNsdXN0ZXJzIGhhcyBzdWJncm91cHMKIyBsZXZlbHMgYXJlIG1haW4gY2VsbCBncm91cHMgCklkZW50cyhzZXUucikgPC0gIkxldmVsMSIKCgojIGZpbmQgdGhlIHJlZmVyZW5jZSBhbmNob3JzCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBzZXUuciwgcXVlcnkgPSBzZXUucSwgZGltcyA9IDE6MjUpCnByaW50KCJnZXR0aW5nIHByZWRpY3Rpb25zIikKcHJlZGljdGlvbnMgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IGFuY2hvcnMsIHJlZmRhdGEgPSBzZXUuciRMZXZlbDEpCnNldS5xIDwtIEFkZE1ldGFEYXRhKHNldS5xLCBtZXRhZGF0YSA9IHByZWRpY3Rpb25zKQpwcmludCh0YWJsZShzZXUucSRwcmVkaWN0ZWQuaWQpKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwpzZXUucSRmYi5wcmVkIDwtIElkZW50cyhzZXUucSkKcHJpbnQodGFibGUoc2V1LnEkZmIucHJlZCkpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ2ZiLnByZWQnKQoKCiMgYWRkIHRoZSB0aHJlc2hvbGQgCnNldS5xJHByZWRpY3RlZC5pZCA8LSBpZmVsc2Uoc2V1LnEkcHJlZGljdGlvbi5zY29yZS5tYXggPiAwLjgwLCBzZXUucSRwcmVkaWN0ZWQuaWQsICJub25lIikKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwpzZXUucSRmYi50aHJlc2ggPC0gSWRlbnRzKHNldS5xKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdmYi50aHJlc2gnLCBsYWJlbCA9IFRSVUUpCnRhYmxlKHNldS5xJGZiLnRocmVzaCkKCiMgbWFrZSB0aGUgdGFibGVzIAp0LmxhYmxlcyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHNldS5xJFJOQV9zbm5fcmVzLjAuMiwgc2V1LnEkZmIudGhyZXNoKSkKdC5sYWJsZXMkRnJlcSA8LSBhcy5kb3VibGUodC5sYWJsZXMkRnJlcSkKZ2dwbG90KHQubGFibGVzLCBhZXMoeSA9IEZyZXEsIHggPSBWYXIxLCBmaWxsID0gVmFyMikpICsgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBzdGF0PSAiaWRlbnRpdHkiKSArIFJvdGF0ZWRBeGlzKCkgCnRvcC5wcmVkLmNlbGx0eXBlIDwtIGFzLmRhdGEuZnJhbWUodC5sYWJsZXMgICU+JSBncm91cF9ieShWYXIxKSAgJT4lIHRvcF9uKDIsIEZyZXEpKQpkZi50b3AgPC0gdG9wLnByZWQuY2VsbHR5cGVbb3JkZXIodG9wLnByZWQuY2VsbHR5cGUkVmFyMSwtdG9wLnByZWQuY2VsbHR5cGUkRnJlcSksXQpyb3cubmFtZXMoZGYudG9wKSA8LSBOVUxMCmRmLnRvcCRJIDwtIHJvdy5uYW1lcyhkZi50b3ApCgojVkxNQyBpcyB2YXNjdWxhciBhbmQgbGVwdG9tZW5pbmdlcwoKIyBhbG1vc3QgZXZlcnl0aGluZyBpcyBwcmVkaWN0ZWQgYXMgJ25vbmUnIHdoZW4gdGhlc2hvbGQgaXMgLjk1IAojIHJ1biBhZ2FpbiB3aXRoIGxvd2VyIHRocmVzaG9sZCAwLjggYW5kIG1hbnkgYXJlIHByZWRpY3RlZCBhcyBSRwoKIyB0cnkgcHJlZGljdGluZyB3aXRoIHRoZSBjbHVzdGVyIGxhYmVscyAKIyBsYXRlciBJIGNhbiBzdWJzZXQgY2VsbCB0eXBlcyBmb3IgdGhlIHJlZmVyZW5jZSBkYXRhCgpJZGVudHMoc2V1LnIpIDwtICJDbHVzdGVycyIKCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBzZXUuciwgcXVlcnkgPSBzZXUucSwgZGltcyA9IDE6MjUpCnByaW50KCJnZXR0aW5nIHByZWRpY3Rpb25zIikKcHJlZGljdGlvbnMgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IGFuY2hvcnMsIHJlZmRhdGEgPSBzZXUuciRDbHVzdGVycykKc2V1LnEgPC0gQWRkTWV0YURhdGEoc2V1LnEsIG1ldGFkYXRhID0gcHJlZGljdGlvbnMpCnByaW50KHRhYmxlKHNldS5xJHByZWRpY3RlZC5pZCkpCgpJZGVudHMoc2V1LnEpIDwtICdwcmVkaWN0ZWQuaWQnCnNldS5xJGZiLnN1Yi5wcmVkIDwtIElkZW50cyhzZXUucSkKcHJpbnQodGFibGUoc2V1LnEkZmIuc3ViLnByZWQpKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdmYi5zdWIucHJlZCcpCgoKIyBhZGQgdGhlIHRocmVzaG9sZCAKc2V1LnEkcHJlZGljdGVkLmlkIDwtIGlmZWxzZShzZXUucSRwcmVkaWN0aW9uLnNjb3JlLm1heCA+IDAuODAsIHNldS5xJHByZWRpY3RlZC5pZCwgIm5vbmUiKQpJZGVudHMoc2V1LnEpIDwtICdwcmVkaWN0ZWQuaWQnCnNldS5xJGZiLnN1Yi50aHJlc2ggPC0gSWRlbnRzKHNldS5xKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdmYi5zdWIudGhyZXNoJywgbGFiZWwgPSBUUlVFKQp0YWJsZShzZXUucSRmYi5zdWIudGhyZXNoKQoKdC5sYWJsZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzZXUucSRSTkFfc25uX3Jlcy4wLjIsIHNldS5xJGZiLnN1Yi50aHJlc2gpKQp0LmxhYmxlcyRGcmVxIDwtIGFzLmRvdWJsZSh0LmxhYmxlcyRGcmVxKQpnZ3Bsb3QodC5sYWJsZXMsIGFlcyh5ID0gRnJlcSwgeCA9IFZhcjEsIGZpbGwgPSBWYXIyKSkgKyBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQ9ICJpZGVudGl0eSIpICsgUm90YXRlZEF4aXMoKSAKdG9wLnByZWQuY2VsbHR5cGUgPC0gYXMuZGF0YS5mcmFtZSh0LmxhYmxlcyAgJT4lIGdyb3VwX2J5KFZhcjEpICAlPiUgdG9wX24oNCwgRnJlcSkpCmRmLnRvcCA8LSB0b3AucHJlZC5jZWxsdHlwZVtvcmRlcih0b3AucHJlZC5jZWxsdHlwZSRWYXIxLC10b3AucHJlZC5jZWxsdHlwZSRGcmVxKSxdCnJvdy5uYW1lcyhkZi50b3ApIDwtIE5VTEwKZGYudG9wJEkgPC0gcm93Lm5hbWVzKGRmLnRvcCkKCmRmLnRvcC5mdCA8LSBkZi50b3AgJT4lIGZpbHRlcihGcmVxID4gMCkKCmBgYAoKUHJlZGljdGlvbnMgd2l0aCB0aHJlc2hvbGRzOgoKMCAtIFJHCjEgLSBSRwoyIC0gbm9uZQozIC0gUkcKNCAtIE5ldXJhbCBwcmVjdXJzb3IKNSAtIFZMTUMgKHZhc2N1bGFyIGFuZCBsZXB0b21lbmluZ2VzKQoKTG9vayBhdCBnZW5lIGxpc3RzIHdpdGgga25vd24gbWFya2VycwoKYGBge3J9CgpJZGVudHMoc2V1LnEpIDwtICdSTkFfc25uX3Jlcy4wLjInCgojIG1hbnkgY2VsbCB0eXBlcyBsaXN0CmZlYXR1cmVfbGlzdCA9IGMoIk1LSTY3IiwiU09YMiIsIlBPVTVGMSIsIkRMWDIiLCJQQVg2IiwiU09YOSIsIkhFUzEiLCJORVMiLCJSQkZPWDMiLCJNQVAyIiwiTkNBTTEiLCJDRDI0IiwiR1JJQTIiLCJHUklOMkIiLCJHQUJCUjEiLCJHQUQxIiwiR0FEMiIsIkdBQlJBMSIsIkdBQlJCMiIsIlRIIiwiQUxESDFBMSIsIkxNWDFCIiwiTlI0QTIiLCJDT1JJTiIsIkNBTEIxIiwiS0NOSjYiLCJDWENSNCIsIklUR0E2IiwiU0xDMUEzIiwiQ0Q0NCIsIkFRUDQiLCJTMTAwQiIsICJQREdGUkEiLCJPTElHMiIsIk1CUCIsIkNMRE4xMSIsIlZJTSIsIlZDQU0xIikKCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBmZWF0dXJlX2xpc3QsIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMikKRG90UGxvdChzZXUucSwgZmVhdHVyZXMgPSBmZWF0dXJlX2xpc3QpICtSb3RhdGVkQXhpcygpCgojIERvcGFtaW5lcmdpYyBtYXJrZXJzClBEX3BvdWxpbiA9IGMoIlRIIiwiU0xDNkEzIiwiU0xDMThBMiIsIlNPWDYiLCJORE5GIiwiU05DRyIsIkFMREgxQTEiLCJDQUxCMSIsIlRBQ1IyIiwiU0xDMTdBNiIsIlNMQzMyQTEiLCJPVFgyIiwiR1JQIiwiTFBMIiwiQ0NLIiwiVklQIikKCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBQRF9wb3VsaW4sIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMikKRG90UGxvdChzZXUucSwgZmVhdHVyZXMgPSBQRF9wb3VsaW4pK1JvdGF0ZWRBeGlzKCkKCmVhbHJ5TmV1ciA9IGMoIkRDWCIsIk5FVVJPRDEiLCJUQlIxIikKcHJvbGlmZXJhdGlvbiA9IGMoIlBDTkEiLCJNS0k2NyIpCm5ldXJhbHN0ZW0gPSBjKCJTT1gyIiwiTkVTIiwiUEFYNiIsIk1BU0gxIikKCmZlYXR1cmVfbGlzdCA8LSBjKCJEQ1giLCJORVVST0QxIiwiVEJSMSIsIlBDTkEiLCJNS0k2NyIsIlNPWDIiLCJORVMiLCJQQVg2IiwiTUFTSDEiKQpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gZmVhdHVyZV9saXN0LCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIpCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gZmVhdHVyZV9saXN0KStSb3RhdGVkQXhpcygpCgoKbWF0X25ldXJvbiA9IGMoIlJCRk9YMyIsIlNZUCIsIkRMRzQ1IiwiVkFNUDEiLCJWQU1QMiIsIlRVQkIzIiwiU1lUMSIsIkJTTiIsIkhPTUVSMSIsIlNMQzE3QTYiKSAKIyBOZXVOIGlzIEZPWDMgLSBSQkZPWDMKIyBQU0Q5NSBhbHNvIFNQLTkwIG9yIERMRzQKIyBWR0xVVDIgaXMgU0xDMTdBNgpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gbWF0X25ldXJvbiwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQojIGNsdXN0ZXIgNCBhbHNvIHNob3cgbWF0dXJlIG5ldXJvbiBtYXJrZXJzCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gbWF0X25ldXJvbikrUm90YXRlZEF4aXMoKQojIGV4Y2l0YXRvcnkgbmV1cm9uIG1hcmtlcnMKZXggPSBjKCJHUklBMiIsIkdSSUExIiwiR1JJQTQiLCJHUklOMSIsIkdSSU4yQiIsIkdSSU4yQSIsIkdSSU4zQSIsIkdSSU4zIiwiR1JJUDEiLCJDQU1LMkEiKQpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gZXgsIHNpemU9MywgYW5nbGUgPTkwLCBncm91cC5iYXIuaGVpZ2h0ID0gMC4wMikKRG90UGxvdChzZXUucSwgZmVhdHVyZXMgPSBleCkrUm90YXRlZEF4aXMoKQojIGluaGliaXRvcnkgbmV1cm9uIG1hcmtlcnMKaW5oID0gYygiR0FEMSIsIkdBRDIiLCAiR0FUMSIsIlBWQUxCIiwiR0FCUjIiLCJHQUJSMSIsIkdCUlIxIiwiR0FCUkIyIiwiR0FCUkIxIiwiR0FCUkIzIiwiR0FCUkE2IiwiR0FCUkExIiwiR0FCUkE0IiwiVFJBSzIiKQpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gaW5oLCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIpCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gaW5oKStSb3RhdGVkQXhpcygpCiMgY2x1c3RlciA0IGlzIG1vcmUgZXhjaXRhdG9yeSB0aGFuIGluaGJpdG9yeSBidXQgbmVpdGhlciBtYXJrZXIgc2V0IGhhcyBtdWNoIGV4cHJlc3Npb24gCgojIyMgZ2xpYSBtYXJrZXJzCm1pY3JvZ2xpYSA9IGMoIlBUUFJDIiwiQUlGMSIsIkFER1JFMSIpICAjIEFER1JFMSBpcyBhIG1pY3JvZ2xpYSBtYXJrZXIgRjQvODAsIENENDUgaXMgUFRQUkMsIGdlbmUgbmFtZSBJQkExIGlzIEFJRjEKYXN0b2xnTlBDcHJvbWljcm8gPSBjKCJHRkFQIiwiUzEwMEIiLCJTTEMxQTIiLCJNQlAiLCJTT1gxMCIsIlNQUDEiLCJEQ1giLCJORVVST0QxIiwiVEJSMSIsIlBDTkEiLCJNS0k2NyIsIlBUUFJDIiwiQUlGMSIsIkFER1JFMSIpCiMgbm90ZSBHTFQxIGlzIEVBQVQyIHdoaWNoIGlzIFNMQzFBMiBnbHV0YXRtYXRlIHRyYW5zcG9ydGVyCiMgZXBpdGhlbGlhbAplcGkgPSBjKCJIRVMxIiwiSEVTNSIsIlNPWDIiLCJTT1gxMCIsIk5FUyIsIkNESDEiLCJOT1RDSDEiKSAjIGUtY2FkaGVyaW4gaXMgQ0RIMQoKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IGFzdG9sZ05QQ3Byb21pY3JvLCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIpCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gYXN0b2xnTlBDcHJvbWljcm8pK1JvdGF0ZWRBeGlzKCkKIyBjbHVzdGVyIDQgaXMgbW9yZSBleGNpdGF0b3J5IHRoYW4gaW5oYml0b3J5IGJ1dCBuZWl0aGVyIG1hcmtlciBzZXQgaGFzIG11Y2ggZXhwcmVzc2lvbiAKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IGVwaSwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IGVwaSkrUm90YXRlZEF4aXMoKQoKIyBhbHNvIGFkZCBSYWRpYWwgZ2xpYSBtYXJrZXIgb3ZlcmxhcCB3aXRoIEdsaWEgYW5kIE5ldXJvbnMKCmZlYXR1cmVzIDwtIGMoIlBUUFJDIiwiQUlGMSIsIkFER1JFMSIsICJWSU0iLCAiVE5DIiwiUFRQUloxIiwiRkFNMTA3QSIsIkhPUFgiLCJMSUZSIiwKICAgICAgICAgICAgICAiSVRHQjUiLCJJTDZTVCIpCkRvSGVhdG1hcChzZXUucSwgZmVhdHVyZXMgPSBmZWF0dXJlcywgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQpEb3RQbG90KHNldS5xLCBmZWF0dXJlcyA9IGZlYXR1cmVzKStSb3RhdGVkQXhpcygpCgojIHJhZGlhbCBnbGlhIG1hcmtlcnMKcmcgPC0gYygiVklNIiwiTkVTIiwiUEFYNiIsIkhFUzEiLCJFQUFUMSIsIk5DQUQxIiwiU09YMiIsIkZBQlA3IikKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IHJnLCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIpCkRvdFBsb3Qoc2V1LnEsIGZlYXR1cmVzID0gcmcpK1JvdGF0ZWRBeGlzKCkKCiMgTlBDIGFuZCByYWRpYWwgZ2xpYSBhcmUgdmVyeSBzaW1pbGFyCgpgYGAKTWFya2VyIGV4cHJlc3Npb24gcHJlZGljdGlvbnMKQ2x1c3RlciAwIC0gdW5rbm93bgpDbHVzdGVyIDEgLSBSRwpDbHVzdGVyIDIgLSB1bmtub3duCkNsdXN0ZXIgMyAtIFJHCmNsdXN0ZXIgNCAtIGltbWF0dXJlIG5ldXJvbnMKQ2x1c3RlciA1IC0gUkcsIG9wYwoKCkNoZWNrIHRoZSBsZXZlbHMgb2YgUk5BIGluIGVhY2ggY2x1c3RlciAKCmBgYHtyfQpWbG5QbG90KHNldS5xLCBmZWF0dXJlcyA9ICJuRmVhdHVyZV9STkEiKQoKYGBgCkNsdXN0ZXIgMCBhbmQgMiBoYXZlIGZld2VyIHNlcXVlbmNlcyB0aGFuIG90aGVyIGdyb3VwcyBhbmQgdGh1cyBubyBtYXJrZXJzClBvc3NpYmx5IHJlbW92ZSB0aGVzZSBpcyB0aGV5IGRvbid0IGNvbWUgdXAgd2l0aCBzb21lIG1hcmtlcnMKCkZpbmQgY2x1c3RlciBtYXJrZXJzCgpgYGB7cn0KSWRlbnRzKHNldS5xKSA8LSAnUk5BX3Nubl9yZXMuMC4yJwpDbHVzdGVyTWFya2VycyA8LSBGaW5kQWxsTWFya2VycyhzZXUucSwgb25seS5wb3MgPSBUUlVFKQoKdG9wNSA8LSBDbHVzdGVyTWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKG49NSwgd3QgPSBhdmdfbG9nMkZDKQpEb0hlYXRtYXAoc2V1LnEsIGZlYXR1cmVzID0gdG9wNSRnZW5lLCBzaXplPTMsIGFuZ2xlID05MCwgZ3JvdXAuYmFyLmhlaWdodCA9IDAuMDIpCgojd3JpdGUuY3N2KENsdXN0ZXJNYXJrZXJzLCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QaGVub0lEL3NjUk5Bc2VxU29ydGVkL0dsaWEyUkdDbHVzdGVyTWFya2Vyc19uZXcuY3N2IikKCklkZW50cyhzZXUucSkgPC0gJ1JOQV9zbm5fcmVzLjAuMScKQ2x1c3Rlck1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMoc2V1LnEsIG9ubHkucG9zID0gVFJVRSkKCnRvcDUgPC0gQ2x1c3Rlck1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuPTUsIHd0ID0gYXZnX2xvZzJGQykKRG9IZWF0bWFwKHNldS5xLCBmZWF0dXJlcyA9IHRvcDUkZ2VuZSwgc2l6ZT0zLCBhbmdsZSA9OTAsIGdyb3VwLmJhci5oZWlnaHQgPSAwLjAyKQoKCmBgYApNYXJrZXJzIG9mIDIgYXJlIG1hdGNoaW5nIHdpdGggNSBwb3NzaWJseSBtZXJnZSB0aGVzZSB0b2dldGhlcgpDbHVzdGVyIDAgbWFya2VycyBkb24ndCBsb29rIHVwIHJlZ3VsYXRlZCBidXQgdGhlIGxpc3QgaXMgbG9uZwoKTG9vayBhdCB0aGUgbGlicmFyaWVzCgpgYGB7cn0KbGlicmFyeShlbnJpY2hSKQoKc2V0RW5yaWNoclNpdGUoIkVucmljaHIiKSAjIEh1bWFuIGdlbmVzCiMgbGlzdCBvZiBhbGwgdGhlIGRhdGFiYXNlcwoKIyBsaWJhcmllcyB3aXRoIGNlbGwgdHlwZXMKCmRiIDwtIGMoJ0Rlc2NhcnRlc19DZWxsX1R5cGVzX2FuZF9UaXNzdWVfMjAyMScsCiAgICAgICAgJ0NlbGxNYXJrZXJfQXVnbWVudGVkXzIwMjEnLCdBemltdXRoX0NlbGxfVHlwZXNfMjAyMScpCgojIGVucmljaHIoZ2VuZXMsIGRhdGFiYXNlcyA9IE5VTEwpCgojSSdsbCBydW4gdGhlIGNsdXN0ZXJzIG9uZSBhdCBhIHRpbWUKCk4xLmMwIDwtIENsdXN0ZXJNYXJrZXJzICU+JSBmaWx0ZXIoY2x1c3RlciA9PSAwICYgYXZnX2xvZzJGQyA+IDApCmdlbmVzIDwtIE4xLmMwJGdlbmUKCk4xLmMwLkVyIDwtIGVucmljaHIoZ2VuZXMsIGRhdGFiYXNlcyA9IGRiKQpwbG90RW5yaWNoKE4xLmMwLkVyW1sxXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMwLkVyW1syXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQpwbG90RW5yaWNoKE4xLmMwLkVyW1szXV0sIHNob3dUZXJtcyA9IDIwLCBudW1DaGFyID0gNDAsIHkgPSAiQ291bnQiLCBvcmRlckJ5ID0gIlAudmFsdWUiKQoKCk4xLkVyLmdlbmVzLjEgPC0gTjEuYzAuRXJbWzFdXSAlPiUgc2VsZWN0KFRlcm0sIEdlbmVzLCBDb21iaW5lZC5TY29yZSkKTjEuRXIuZ2VuZXMuMQoKTjEuRXIuZ2VuZXMuMiA8LSBOMS5jMC5FcltbMl1dICU+JSBzZWxlY3QoVGVybSwgR2VuZXMsIENvbWJpbmVkLlNjb3JlKQpOMS5Fci5nZW5lcy4yCgpOMS5Fci5nZW5lcy4zIDwtIE4xLmMwLkVyW1szXV0gJT4lIHNlbGVjdChUZXJtLCBHZW5lcywgQ29tYmluZWQuU2NvcmUpCk4xLkVyLmdlbmVzLjMKCgoKCgoKYGBgCgpUaGUgYWR1bHQgYnJhaW4gZG9lc24ndCBwcmVkaWN0IHJhZGlhbCBnbGlhIC0gdGhlcmUgYXJlIHJhZGlhbCBnbGlhIGJ1dCBJIGJlbGlldmUgdGhlc2UgYXJlIGRpZmZlcmVudCBmcm9tIHRoZSAnbmV1cm9ibGFzdCcgdHlwZSByYWRpYWwgZ2xpYQoKSSB3aWxsIHVzZSBhIGRldmVsb3BpbmcgYnJhaW4gcmVmZXJlbmNlCgpgYGB7cn0KRGltUGxvdChzZXUucSkKCmBgYAoKCgpgYGB7cn0KCnNldS5xIDwtIHJlYWRSRFMocGFzdGUocGF0aHdheSwiR2xpYTJMYWJsZWRTZXUwMzEwMjAyMi5SRFMiLHNlcCA9ICIiKSkKCiMgbWlkYnJhaW4gYW5kIHN0cmlhdHVtCgpzZXUuciA8LSByZWFkUkRTKCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QdWJsaWNEYXRhL0JoYWR1cmlfd2hvbGVCcmFpbi9CaGFkdXJpX21pZGJyYWluX3N0cmlhdHVtLlJEUyIpCgpJZGVudHMoc2V1LnIpIDwtICJjZWxsX2NsdXN0ZXIiCgojIGZpbmQgdGhlIHJlZmVyZW5jZSBhbmNob3JzCmFuY2hvcnMgPC0gRmluZFRyYW5zZmVyQW5jaG9ycyhyZWZlcmVuY2UgPSBzZXUuciwgcXVlcnkgPSBzZXUucSwgZGltcyA9IDE6MjUpCnByaW50KCJnZXR0aW5nIHByZWRpY3Rpb25zIikKcHJlZGljdGlvbnMgPC0gVHJhbnNmZXJEYXRhKGFuY2hvcnNldCA9IGFuY2hvcnMsIHJlZmRhdGEgPSBzZXUuciRjZWxsX2NsdXN0ZXIpCnNldS5xIDwtIEFkZE1ldGFEYXRhKHNldS5xLCBtZXRhZGF0YSA9IHByZWRpY3Rpb25zKQpwcmludCh0YWJsZShzZXUucSRwcmVkaWN0ZWQuaWQpKQoKSWRlbnRzKHNldS5xKSA8LSAncHJlZGljdGVkLmlkJwpzZXUucSRCaGEubWlkLnN0cmkucHJlZCA8LSBJZGVudHMoc2V1LnEpCnByaW50KHRhYmxlKHNldS5xJEJoYS5taWQuc3RyaS5wcmVkKSkKCgpzZXUucSRwcmVkaWN0ZWQuaWQgPC0gaWZlbHNlKHNldS5xJHByZWRpY3Rpb24uc2NvcmUubWF4ID4gMC45NSwgc2V1LnEkcHJlZGljdGVkLmlkLCAibm9uZSIpCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKc2V1LnEkQmhhLm1pZC5wcmVkLnRocmVzaCA8LSBJZGVudHMoc2V1LnEpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ0JoYS5taWQucHJlZC50aHJlc2gnLCBsYWJlbCA9IFRSVUUpCnRhYmxlKHNldS5xJEJoYS5taWQucHJlZC50aHJlc2gpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ0JoYS5taWQucHJlZC50aHJlc2gnKQoKCiMgcmVhZCBpbiB0aGUgcmVmZXJlbmNlIGRhdGFzZXQKIyB3aG9sZSBicmFpbiBCaGFkdXJpIGRvd24gc2FtcGxlZApzZXUuciA8LSByZWFkUkRTKCIvVXNlcnMvcmhhbGVuYXRob21hcy9Eb2N1bWVudHMvRGF0YS9zY1JOQXNlcS9QdWJsaWNEYXRhL0JoYWR1cmlfd2hvbGVCcmFpbi9CaGFkdXJpX2Rvd25zYW1wbGUuUkRTIikKCklkZW50cyhzZXUucikgPC0gImNlbGxfY2x1c3RlciIKCiMgZmluZCB0aGUgcmVmZXJlbmNlIGFuY2hvcnMKYW5jaG9ycyA8LSBGaW5kVHJhbnNmZXJBbmNob3JzKHJlZmVyZW5jZSA9IHNldS5yLCBxdWVyeSA9IHNldS5xLCBkaW1zID0gMToyNSkKcHJpbnQoImdldHRpbmcgcHJlZGljdGlvbnMiKQpwcmVkaWN0aW9ucyA8LSBUcmFuc2ZlckRhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgcmVmZGF0YSA9IHNldS5yJGNlbGxfY2x1c3RlcikKc2V1LnEgPC0gQWRkTWV0YURhdGEoc2V1LnEsIG1ldGFkYXRhID0gcHJlZGljdGlvbnMpCnByaW50KHRhYmxlKHNldS5xJHByZWRpY3RlZC5pZCkpCgpJZGVudHMoc2V1LnEpIDwtICdwcmVkaWN0ZWQuaWQnCnNldS5xJEJoYS5wcmVkIDwtIElkZW50cyhzZXUucSkKcHJpbnQodGFibGUoc2V1LnEkQmhhLnByZWQpKQpEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdCaGEucHJlZCcpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ3N1Ymdyb3VwcycpCgpzZXUucSRwcmVkaWN0ZWQuaWQgPC0gaWZlbHNlKHNldS5xJHByZWRpY3Rpb24uc2NvcmUubWF4ID4gMC45NSwgc2V1LnEkcHJlZGljdGVkLmlkLCAibm9uZSIpCklkZW50cyhzZXUucSkgPC0gJ3ByZWRpY3RlZC5pZCcKc2V1LnEkQmhhLm1pZC5wcmVkLnRocmVzaCA8LSBJZGVudHMoc2V1LnEpCkRpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ0JoYS5wcmVkLnRocmVzaCcsIGxhYmVsID0gVFJVRSkKdGFibGUoc2V1LnEkQmhhLm1pZC5wcmVkLnRocmVzaCkKRGltUGxvdChzZXUucSwgZ3JvdXAuYnkgPSAnQmhhLnByZWQudGhyZXNoJykKCgpgYGAKCgoKCgpBZGQgc29tZSBjZWxsIHR5cGUgYW5ub3RhdGlvbnMKCmBgYHtyfQoKSWRlbnRzKHNldS5xKSA8LSAnUk5BX3Nubl9yZXMuMC4yJwoKY2x1c3Rlci5pZHMgPC0gYygiR2xpYTEiLCJSRzEiLCJHbGlhMiIsIlJHMiIsIk5ldXJvbnNJbW1hdHVyZSIsIlJHMyIpCgpuYW1lcyhjbHVzdGVyLmlkcykgPC0gbGV2ZWxzKHNldS5xKQpzZXUucSA8LSBSZW5hbWVJZGVudHMoc2V1LnEsIGNsdXN0ZXIuaWRzKQpzZXUucSRzdWJncm91cHMgPC0gSWRlbnRzKHNldS5xKQoKI0RpbVBsb3Qoc2V1LnEsIGdyb3VwLmJ5ID0gJ1JOQV9zbm5fcmVzLjAuMicsIGxhYmVsID0gVFJVRSkKRGltUGxvdChzZXUucSwgcmVkdWN0aW9uID0gInVtYXAiLCBsYWJlbCA9IFRSVUUsIGdyb3VwLmJ5ID0gJ3N1Ymdyb3VwcycsIHJlcGVsID0gVFJVRSkKCgoKYGBgCgpgYGB7cn0KIyBzYXZlIGZpbGUKc2F2ZVJEUyhzZXUucSwgIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BoZW5vSUQvc2NSTkFzZXFTb3J0ZWQvb2Jqcy9HbGlhMkxhYmxlZFNldTAzMTAyMDIyLlJEUyIpCgpgYGAKCk1haW4gY2VsbCBncm91cHMKCmBgYHtyfQoKSWRlbnRzKHNldS5xKSA8LSAnUk5BX3Nubl9yZXMuMC4yJwoKY2x1c3Rlci5pZHMgPC0gYygiUmFkaWFsIEdsaWEiLCJSYWRpYWwgR2xpYSIsIlJhZGlhbCBHbGlhIiwiUmFkaWFsIEdsaWEiLCJOUEMiLCJPdGhlciIpCgpuYW1lcyhjbHVzdGVyLmlkcykgPC0gbGV2ZWxzKHNldS5xKQpzZXUucSA8LSBSZW5hbWVJZGVudHMoc2V1LnEsIGNsdXN0ZXIuaWRzKQpzZXUucSRDZWxsX1R5cGVzIDwtIElkZW50cyhzZXUucSkKCiNEaW1QbG90KHNldS5xLCBncm91cC5ieSA9ICdSTkFfc25uX3Jlcy4wLjInLCBsYWJlbCA9IFRSVUUpCkRpbVBsb3Qoc2V1LnEsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBUUlVFLCBncm91cC5ieSA9ICdDZWxsX1R5cGVzJywgcmVwZWwgPSBUUlVFKQoKc2F2ZVJEUyhzZXUucSwgIi9Vc2Vycy9yaGFsZW5hdGhvbWFzL0RvY3VtZW50cy9EYXRhL3NjUk5Bc2VxL1BoZW5vSUQvc2NSTkFzZXFTb3J0ZWQvb2Jqcy9HbGlhMkxhYmxlZFNldTAzMTAyMDIyLlJEUyIpCgpgYGAKClByb3BvcnRpb25zIG9mIGNlbGwgdHlwZXMKCmBgYHtyfQoKdGFibGUoc2V1LnEkQ2VsbF9UeXBlcykKZGltKHNldS5xKQoKcHJwIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoc2V1LnEkQ2VsbF9UeXBlcykpCnBycAoKcHJwJHByb3AgPC0gcHJwJEZyZXEvc3VtKHBycCRGcmVxKSoxMDAKcHJwJFNhbXBsZSA8LSAnUmFkaWFsR2xpYScKcHJwCgoKYGBgCgpJJ2xsIGNhbGN1bGF0ZSB0aGUgcHJvcG9ydGlvbnMgZm9yIGVhY2ggY2VsbCB0eXBlIGFuZCBtYWtlIGEgdGFibGUgb3IgcGxvdCBpbiB0aGUgY29tcGFyaXNvbiB3b3JrYm9vay4gCgoKCg==